I have found these related issues/pull requests
N/A
Description
The caching_sha2_password plugin exists for one reason: after an initial full authentication (which requires TLS or a 2048-bit RSA decryption on the server), subsequent connections from the same user hit a server-side cache and skip the expensive key exchange entirely.
That's the "caching" in the name. The fast-auth scramble — XOR(SHA256(pw), SHA256(SHA256(SHA256(pw)) ‖ nonce)) — is designed so the server can cheaply validate it against its cached SHA256(SHA256(pw)) and respond with fast_auth_success (0x03) in a single round trip.
sqlx-mysql implements the scramble with the nonce and hash concatenated in the wrong order, so no spec-compliant server can ever validate it. Every sqlx connection to a MySQL server using caching_sha2_password takes the full-auth path — forever. The cache never helps.
The entire optimization the plugin was built to provide is silently defeated for sqlx users.
Two consecutive sqlx connections to stock MySQL 8.4 with the same user. The server responds with perform_full_authentication (0x04) both times — the second connection should have hit the cache and received fast_auth_success (0x03):
Root cause
auth.rs
ctx.update(nonce.first_ref());
ctx.update(nonce.last_ref());
ctx.update(pw_hash_hash);
This computes SHA256(nonce ‖ SHA256(SHA256(pw))). MySQL's computes SHA256(SHA256(SHA256(pw)) ‖ nonce). Since SHA-256 is not concat-commutative, the two hashes never match, and the server's XOR can never recover SHA256(pw).
Reproduction steps
- collect TCP dump / Wireshark
- Execute:
export DATABASE_URL='mysql://root:[email protected]:3306/test?ssl-mode=DISABLED'; sqlx database create
SQLx version
sqlx-cli 0.8.6
Enabled SQLx features
N/a
Database server and version
MySQL 8.4
Operating system
MacOS
Rust version
N/a
I have found these related issues/pull requests
N/A
Description
The caching_sha2_password plugin exists for one reason: after an initial full authentication (which requires TLS or a 2048-bit RSA decryption on the server), subsequent connections from the same user hit a server-side cache and skip the expensive key exchange entirely.
That's the "caching" in the name. The fast-auth scramble — XOR(SHA256(pw), SHA256(SHA256(SHA256(pw)) ‖ nonce)) — is designed so the server can cheaply validate it against its cached SHA256(SHA256(pw)) and respond with fast_auth_success (0x03) in a single round trip.
sqlx-mysql implements the scramble with the nonce and hash concatenated in the wrong order, so no spec-compliant server can ever validate it. Every sqlx connection to a MySQL server using caching_sha2_password takes the full-auth path — forever. The cache never helps.
The entire optimization the plugin was built to provide is silently defeated for sqlx users.
Two consecutive sqlx connections to stock MySQL 8.4 with the same user. The server responds with perform_full_authentication (0x04) both times — the second connection should have hit the cache and received fast_auth_success (0x03):
Root cause
auth.rs
This computes
SHA256(nonce ‖ SHA256(SHA256(pw))). MySQL's computesSHA256(SHA256(SHA256(pw)) ‖ nonce). Since SHA-256 is not concat-commutative, the two hashes never match, and the server's XOR can never recover SHA256(pw).Reproduction steps
SQLx version
sqlx-cli 0.8.6
Enabled SQLx features
N/a
Database server and version
MySQL 8.4
Operating system
MacOS
Rust version
N/a