Public Key Retrieval is not allowed — how to fix
java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110)
Caused by: com.mysql.cj.exceptions.UnableToConnectException: Public Key Retrieval is not allowed
Quick fix: Add allowPublicKeyRetrieval=true to the JDBC URL together with useSSL=false for local development: jdbc:mysql://localhost:3306/mydb?allowPublicKeyRetrieval=true&useSSL=false. In production keep TLS on (sslMode=REQUIRED) instead, which avoids the key exchange.
What it means
MySQL 8 authenticates users with caching_sha2_password by default. The client must send the password either over TLS, or encrypted with the server's RSA public key. With SSL disabled (useSSL=false) and no public key configured, Connector/J would have to ask the server for the key. Because that request could be intercepted (a man-in-the-middle could hand out its own key), Connector/J blocks it unless you opt in — hence this error.
It often appears "randomly": once a user has logged in successfully, the server caches the auth and later connections succeed; after a server restart, the cache is empty and the error returns.
Fix 1: allow public key retrieval (local/dev)
Add allowPublicKeyRetrieval=true to the URL:
jdbc:mysql://localhost:3306/mydb?allowPublicKeyRetrieval=true&useSSL=false
Spring Boot application.properties:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC
spring.datasource.username=app
spring.datasource.password=secret
In YAML, quote the URL because of the & and ? characters:
spring:
datasource:
url: "jdbc:mysql://localhost:3306/mydb?allowPublicKeyRetrieval=true&useSSL=false"
DBeaver / IntelliJ: edit the connection → Driver properties → set allowPublicKeyRetrieval to true (and useSSL to false for a local server without TLS).
Fix 2: use TLS instead (production)
When the connection is encrypted, the password travels inside TLS and no public key is needed. MySQL 8 generates self-signed certificates automatically, so TLS usually works out of the box:
jdbc:mysql://db.example.com:3306/mydb?sslMode=REQUIRED
For full protection against MITM, verify the certificate with sslMode=VERIFY_IDENTITY plus a truststore (trustCertificateKeyStoreUrl=file:/path/truststore.jks&trustCertificateKeyStorePassword=...).
In Connector/J 8.0.13+ sslMode replaces the older useSSL/requireSSL/verifyServerCertificate properties.
Fix 3: give the client the server's public key
Safer than retrieval without TLS: copy the key and point the driver at it.
SHOW STATUS LIKE 'Caching_sha2_password_rsa_public_key';
Save the PEM to a file, then:
jdbc:mysql://host:3306/mydb?useSSL=false&serverRSAPublicKeyFile=/etc/app/mysql_pub.pem
Fix 4: switch the user to mysql_native_password (legacy)
Only if you can't change the client (very old drivers):
ALTER USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY 'secret';
mysql_native_password is deprecated in MySQL 8.0 and disabled by default from 8.4, removed in 9.0 — prefer Fixes 1–3.
Docker tip
With the mysql:8 image, a fresh container has an empty auth cache, so the first JDBC connection after every docker compose up hits this error. Put allowPublicKeyRetrieval=true in the URL for the dev profile, or enable TLS.
Last updated 2026-11-02.