MySQL Pass-Through Authentication
Pass-through authentication lets ProxySQL learn a MySQL credential by validating it against a backend. It is
useful when ProxySQL should route a user without storing that user’s password in mysql_users, but it expands
the authentication and in-memory credential surface and must be enabled deliberately.
Availability
Pass-through authentication can be enabled in ProxySQL 3.1.10 and 4.0.10. ProxySQL 3.0.10 exposes the variables
but is the Stable tier: loading mysql-passthrough_auth_enabled=true logs an error and forces the runtime value
back to false.
The master gate mysql-passthrough_auth_enabled
defaults to false. All subordinate pass-through settings are ineffective while it remains off.
Security Model
For a cache miss, ProxySQL requests the client’s cleartext credential during the
caching_sha2_password full-authentication exchange and uses a fresh backend connection as the credential
verdict. The frontend connection must use TLS. Keep
mysql-passthrough_auth_require_tls
at its default true, and configure use_ssl=1 on target backend rows so the validation connection is also
protected.
A successful credential is retained as cleartext in ProxySQL process memory. The read-only statistics never expose it, but process-memory access remains sensitive. Learned credentials:
- are not written to
mysql_usersor any other Admin table; - are not persisted to disk and disappear on restart; and
- are local to one ProxySQL process and are not synchronized by ProxySQL Cluster.
Use least-privilege Admin access, restrict the frontend listener, protect core dumps and process memory, and set a finite cache TTL when operationally appropriate.
Supported Authentication Flow
The released learning flow supports caching_sha2_password full authentication. On a cache miss ProxySQL:
- checks the master gate, user-mode gate, TLS, username policy, failure limits, and in-flight limit;
- receives the credential over the TLS-protected frontend connection;
- forces a new connection to the selected backend hostgroup so the submitted credential is actually tested;
- caches the credential and returns the authenticated backend connection to the normal pool on success; and
- completes frontend authentication. The client’s first query then follows normal lazy backend acquisition.
The probe counts against both the target mysql_servers.max_connections and the pass-through in-flight cap.
Failures use a generic access-denied response so backend topology and error detail are not disclosed.
Empty-Password Rows
An existing mysql_users row with password='' enters pass-through only when the master gate and
mysql-passthrough_auth_empty_password
are both true. Its default_hostgroup selects the validation backend and its normal user settings remain the
routing policy.
Enabling this mode changes the meaning of the empty password: it becomes a pass-through signal, not permission for passwordless login. Clients must send a valid backend password. Do not enable the mode if an existing deployment intentionally relies on passwordless empty-password rows.
Unknown Users
mysql-passthrough_auth_unknown_users
defaults to false. When enabled, a username absent from mysql_users can be validated against
mysql-passthrough_default_hg.
ProxySQL still does not create a mysql_users row.
Routing defaults are synthesized again on every connect. The default schema comes from
mysql-passthrough_default_schema,
falling back to mysql-default_schema when empty. Restrict the allowed population with
mysql-passthrough_auth_username_pattern.
The pattern is a full-match allowlist for every pass-through attempt, including empty-password rows, and is
especially important for unknown users. An empty pattern permits every username and emits a security warning
when unknown-user mode is loaded.
Configuration
This example enables the safer, explicit empty-password-row flow. Replace the username, password handling, hostgroup, and listener TLS configuration for your environment:
UPDATE mysql_servers
SET use_ssl = 1
WHERE hostgroup_id = 30;
SET mysql-default_authentication_plugin = 'caching_sha2_password';
SET mysql-passthrough_auth_enabled = 'true';
SET mysql-passthrough_auth_empty_password = 'true';
SET mysql-passthrough_auth_unknown_users = 'false';
SET mysql-passthrough_auth_require_tls = 'true';
SET mysql-passthrough_auth_cache_ttl_s = 3600;
LOAD MYSQL SERVERS TO RUNTIME;
LOAD MYSQL VARIABLES TO RUNTIME;
SELECT variable_value
FROM runtime_global_variables
WHERE variable_name = 'mysql-passthrough_auth_enabled';
The query must return true. If it remains false, stop here: do not create, load, or save an empty-password
user row. In particular, ProxySQL 3.0.10 Stable rejects the enabled value during the runtime load and forces it
back to false. Also inspect the LOAD MYSQL VARIABLES TO RUNTIME result for rejected or unknown settings.
Only after the runtime master gate is confirmed as true, persist the verified variables and backend settings,
then create and persist the pass-through user. This order prevents the empty-password row from existing on disk
without its required gate:
SAVE MYSQL VARIABLES TO DISK;
SAVE MYSQL SERVERS TO DISK;
INSERT INTO mysql_users (username, password, default_hostgroup, active)
VALUES ('app_user', '', 30, 1);
LOAD MYSQL USERS TO RUNTIME;
SAVE MYSQL USERS TO DISK;
For an unknown-user flow, do not insert the user row and add these settings before loading variables:
SET mysql-passthrough_auth_unknown_users = 'true';
SET mysql-passthrough_auth_empty_password = 'false';
SET mysql-passthrough_default_hg = 30;
SET mysql-passthrough_default_schema = 'app';
SET mysql-passthrough_auth_username_pattern = '^app_[a-z0-9_]+$';
Variable defaults, accepted ranges, and tier availability are in the
canonical MySQL variables reference.
User and backend fields are defined in mysql_users
and mysql_servers.
Credential Cache and Expiration
mysql-passthrough_auth_cache_ttl_s
defaults to 0, meaning no time-based expiration. A positive TTL is checked lazily on lookup; expired entries
are removed and the next connection must validate again.
If a later query-path backend connection rejects a learned credential with access denied, ProxySQL evicts that user immediately. The current client connection fails, and the next connection revalidates. Operators can also flush the whole cache or one user:
PROXYSQL FLUSH PASSTHROUGH_AUTH_CACHE;
PROXYSQL FLUSH PASSTHROUGH_AUTH_CACHE FOR USER 'app_user';
Disabling the master gate prevents new pass-through attempts but does not erase existing entries. Flush them explicitly when the operational intent is to remove learned credentials.
Failure Limits
Pass-through uses a per-username and per-client-IP sliding failure window plus a global in-flight probe cap. Credential-class backend failures count toward the sliding limits; transport failures and timeouts do not. Further attempts are rejected until the applicable window clears.
The controls are:
mysql-passthrough_auth_max_failures_per_usermysql-passthrough_auth_max_failures_per_ipmysql-passthrough_auth_failure_window_smysql-passthrough_auth_failure_map_capmysql-passthrough_auth_max_inflight_probes
Keep the defaults until observed traffic justifies a change. Raising the limits expands the credential-stuffing and backend-load budget.
Verification and Statistics
Verify runtime settings, cache state, and health counters from the Admin interface:
SELECT variable_name, variable_value
FROM runtime_global_variables
WHERE variable_name LIKE 'mysql-passthrough%'
ORDER BY variable_name;
SELECT username, learned_at, age_s, hostgroup_probed
FROM stats_mysql_passthrough_auth_cache;
SELECT metric_name, metric_value
FROM stats_mysql_passthrough_auth_metrics;
The cache table contains usernames and timing/hostgroup metadata, never passwords or hashes. Treat it as
sensitive when unknown users are enabled because it reveals accounts that successfully authenticated. Watch
probes_failed_credentials, probes_failed_transport, lockout counters, inflight_cap_rejects, and
cache_invalidations alongside successful probes and hits. See the canonical
pass-through statistics reference.
Unsupported Cases
mysql_native_passwordandmysql_clear_passwordcannot initiate released pass-through learning.COM_CHANGE_USERto a user that requires pass-through is rejected.- A non-TLS frontend connection cannot complete the supported learning flow.
- ProxySQL 3.0.10 Stable cannot enable the master gate.
- Learned credentials do not persist or replicate between ProxySQL nodes.
These exclusions apply to the released 3.1.10 and 4.0.10 behavior; do not plan deployments around unreleased authentication paths.
Troubleshooting
- Master gate remains false: confirm the running tier. Stable 3.0.10 deliberately rejects enabling it; install 3.1.10 or 4.0.10.
- Client receives access denied before a backend probe: confirm frontend TLS, the empty-row or unknown-user gate, and the username pattern. Invalid patterns deny access.
- Probe starts but authentication fails: verify the backend account, password, target hostgroup, online
server capacity, backend TLS, and
caching_sha2_passwordsupport. - A valid user becomes temporarily locked out: inspect the per-user/IP counters and failure window. Fix the credential failures instead of immediately raising limits.
- Password rotation causes one failed connection: query
cache_invalidations; the rejected learned entry is evicted and the next connection should revalidate. Flush the user explicitly to preempt that failure. - Different nodes behave differently: the credential cache is node-local. Warm each node through normal authentication or expect the first connection on each node to validate independently.