The mysql_router plugin lets a ProxySQL 4.0 build register with an InnoDB
Cluster as a MySQL Router-compatible instance. It reads MySQL InnoDB Cluster
Metadata 2.2, maintains ProxySQL-native servers, users, hostgroups, rules, and
listeners, and reconciles them as topology and account state change.
Build the core and the real plugin with the same feature tiers and toolchain:
make PROXYSQL40=1 PROXYSQL31=1 -j2
make PROXYSQL40=1 PROXYSQL31=1 -C plugins/mysql_router all
sudo make installThe source-tree artifact is
plugins/mysql_router/proxysql_mysql_router.so; make install places it in
/usr/lib/proxysql/plugins/proxysql_mysql_router.so. The plugin is part of the
ProxySQL 4.0 build surface and is not yet included in release packages.
Supply the metadata password through a readable file descriptor. Passwords in the bootstrap URI are rejected.
exec 3< /run/secrets/mysql-router-bootstrap-password
proxysql --load-plugin=mysql_router \
--bootstrap cluster_admin@db1.example:3306 \
--bootstrap-password-fd=3 \
--router-name=proxysql-router-1Bootstrap uses the MySQL Shell-compatible registration and account contracts,
stores the service credential through the core encrypted-secret service, and
publishes the first complete topology before marking local bootstrap complete.
Bootstrap is a one-shot configuration step: it writes the configuration to disk,
including the Router endpoints in mysql-interfaces, and then exits. A bootstrap
run never opens client listeners and never serves traffic. After bootstrap, start
ProxySQL normally while continuing to load the plugin:
proxysql --load-plugin=mysql_routerThe plugin resumes from its persisted identity, starts its reconciliation
worker, and opens the Router-owned listener gates only after a complete live
generation is available. MYSQL ROUTER RECONCILE requests an immediate
reconciliation through the Admin interface.
Bootstrap accepts the MySQL Router TLS options for the metadata connection:
--ssl-mode, --ssl-ca, --ssl-capath, --ssl-cert, --ssl-key,
--ssl-cipher, --ssl-crl and --ssl-crlpath. Bootstrap stores them in
mysql_router_config (metadata_ssl_mode, metadata_ssl_ca, ...,
metadata_ssl_crlpath). The reconciler then uses the same TLS settings for
every later metadata, health and user-sync connection.
| Mode | Behavior |
|---|---|
DISABLED |
Plaintext. |
PREFERRED (default) |
Requests TLS, and continues in plaintext only if the server does not offer it. |
REQUIRED |
Requires TLS. The connection fails if TLS is not negotiated. The certificate is not verified. See the note below. |
VERIFY_CA |
Requires TLS and verifies the server certificate against --ssl-ca/--ssl-capath. Connector/C also checks the hostname, so this is as strict as VERIFY_IDENTITY. |
VERIFY_IDENTITY |
Requires TLS and verifies the certificate chain and the server hostname. |
VERIFY_CA and VERIFY_IDENTITY require --ssl-ca or --ssl-capath. They
never fall back to the system trust store. A client certificate and its key
must be given together. Configurations that break these rules are rejected
both by bootstrap and when the reconciler loads its configuration. Deployments
bootstrapped before these keys existed have no metadata_ssl_* rows and use
PREFERRED.
With REQUIRED, Connector/C 3.3 cannot refuse a server that offers no TLS
before authenticating. ProxySQL checks for TLS once the connection is
established and closes it if TLS was not negotiated, but by then the server has
already received the metadata user name and the password's challenge response.
The password itself is not sent unless the metadata account uses a cleartext
authentication plugin. As in MySQL, REQUIRED does not verify the server, so
it protects only against passive eavesdropping, not against an active attacker.
Use VERIFY_CA or VERIFY_IDENTITY when the network path is not trusted: in
those modes, Connector/C refuses a server without TLS before it authenticates.
| Port | Behavior |
|---|---|
| 6033 | Existing ProxySQL MySQL endpoint; fully operator-owned and query-aware |
| 6446 | Router Classic read/write endpoint; writer route, then fast-forward after the first COM_QUERY |
| 6447 | Router Classic read-only endpoint; eligible reader route, then fast-forward after the first COM_QUERY |
| 6450 | Router Classic read/write-split endpoint; remains query-aware and uses native ProxySQL query rules |
The port numbers above are defaults. --conf-base-port and the listener
options can move the three Router endpoints; behavior follows the compiled
endpoint intent, not a hard-coded port comparison.
Like every other MySQL listener in ProxySQL, the Router endpoints are opened only
at startup. Publication stores the Router endpoints in mysql-interfaces (memory
and disk) but never opens or closes a listener at runtime. If a publication stages
a mysql-interfaces value that differs from the active listeners, ProxySQL logs a
warning, and the change takes effect at the next restart.
The direct rules use the native query-rule attribute
{"switch_to_fast_forward":true}. Operators can insert a lower rule ID with
apply=1 to override a Router default for selected users or traffic. Such
operator rules remain operator-owned and are preserved byte-for-byte during
Router reconciliation. The 6450 rules do not contain the fast-forward action,
so normal ProxySQL query processing, hostgroup selection, and transaction
tracking remain available there.
Each cluster member reports Group Replication health from its own point of
view. A member cut off in a minority partition still answers queries, but it
sees itself ONLINE and its peers UNREACHABLE, so its view has no quorum. The
reconciler does not publish such a view while another member may still have
quorum. It tries the other known members first and uses the first view that has
quorum. Only if no reachable member reports quorum does it apply the cluster's
unreachable_quorum_allowed_traffic policy to the view it has. This applies
both to normal metadata reads and to the health-only fallback used while
metadata is unavailable.
The plugin allocates eight hostgroups for stable writer/reader routes and internal Group Replication, asynchronous-reader, and offline roles. It also owns its five baseline rules, its three listener endpoints, and only the users that were successfully normalized from metadata. Ownership is recorded in the core plugin ledger in both memory and disk.
Publication is one atomic generation across main, disk, and live runtime (servers, users, and query rules; listeners change only at restart). Unrelated operator servers, users, rules, interfaces, and attributes are not replaced. A collision with an operator-owned identity fails that object closed; the plugin reports the conflict rather than taking ownership. Explicit user release keeps the local row and transfers ownership to the operator.
Useful Admin queries include:
SELECT * FROM runtime_mysql_router_status;
SELECT * FROM runtime_mysql_router_topology;
SELECT * FROM runtime_mysql_router_hostgroups;
SELECT * FROM runtime_mysql_router_users;
SELECT * FROM stats_mysql_router_refresh ORDER BY refresh_id DESC LIMIT 20;
SELECT * FROM stats_mysql_router_errors ORDER BY last_seen DESC;
SELECT rule_id,proxy_port,destination_hostgroup,attributes,comment
FROM runtime_mysql_query_rules WHERE comment LIKE 'mysql_router:%';runtime_mysql_router_status reports metadata and registration availability,
active topology/user generations, gate readiness, staleness, collisions, and
the last error. Closed listener gates reject an accepted connection before a
session or MySQL handshake is created; they reopen only after the plugin has a
complete usable generation.
The current foundation supports InnoDB Cluster Metadata 2.2, Group Replication members, and MySQL Shell-managed asynchronous read replicas. Routing Guidelines are deliberately not imported in this change; follow-up issue #6145 tracks conversion to or direct use of ProxySQL-native routing policy.
Current exclusions are MySQL X Router endpoints, takeover of an existing MySQL Router deployment, InnoDB ReplicaSet, ClusterSet, and release packaging. Each requires its own reviewed implementation and acceptance plan.