Let's get started with a Microservice Architecture with Spring Cloud:
Fix the Java-MySQL Connection Exception: Public Key Retrieval is not allowed
Last updated: February 25, 2026
1. Overview
While connecting a Java application to a MySQL 8 database, we may see a common exception:
Public Key Retrieval is not allowed
The message above doesn’t indicate a legacy bug. Instead, it’s a security safeguard by modern MySQL and MySQL Connector/J. It usually occurs during authentication when the JDBC driver can’t safely retrieve the MySQL server’s RSA public key.
In this tutorial, we’ll see different aspects related to the Public Key Retrieval is not allowed message:
- when and why the error occurs
- how to reproduce it on a modern MySQL setup
- which fixes are available for the error
Let’s explore each of the above points.
2. When and Why the Error Occurs
MySQL uses caching_sha2_password as its new default authentication plugin for versions 8.0.4 and above. Critically, this plugin is more secure than its older counterparts.
When a client connects without SSL, the new authentication method requires password exchange using an RSA public key. This key is used to encrypt the password during exchange. For security reasons, MySQL Connector/J doesn’t allow automatic public key retrieval unless we explicitly configure it.
Generally, the error occurs when some of the conditions are true:
- authentication uses caching_sha2_password
- SSL is off or not available
- public key retrieval isn’t explicitly allowed
As a result, the driver blocks the authentication process and throws the Public Key Retrieval is not allowed exception.
3. Reproducing the Error
Let’s try to reproduce the error in a local machine environment.
3.1. Test Setup
For this setup, we’re using two machines. On one machine, we have a Java installation. The other has a MySQL server.
Let’s call them A and B:
- Machine A: MySQL 8 server with the IP 192.168.29.116
- Machine B: Java client with the IP 192.168.29.21
After that, we configure the MySQL server.
3.2. MySQL Server Configuration
Let’s ensure MySQL listens on all interfaces.
For this, we edit the MySQL config file on machine A:
$ sudo cat /etc/mysql/mysql.conf.d/mysqld.cnf
...
bind-address = 0.0.0.0
...
Afterward, we restart MySQL:
$ sudo systemctl restart mysql
Now, everything should be in place.
3.3. Sample Database
To perform the setup, we create a database, mydb, and a user, testuser:
mysql> CREATE DATABASE mydb;
mysql> CREATE USER 'testuser'@'%'IDENTIFIED BY 'testpass';
mysql> GRANT ALL PRIVILEGES ON mydb.* TO 'testuser'@'%';
FLUSH PRIVILEGES;
The new user now has all the privileges on the database mydb. Moreover, the authentication uses the default MySQL 8 authentication plugin:
mysql > SELECT user, host, plugin FROM mysql.user WHERE user='testuser';
The plugin must be of type caching_sha2_password.
3.4. Triggering the Error with Java Test Code
Let’s try to trigger the error on machine B.
For this, we try to connect to a MySQL 8 instance with a standard JDBC connection string.
Specifically, we attempt a connection without SSL or specific RSA configurations:
import java.sql.Connection;
import java.sql.DriverManager;
public class TestConnection {
public static void main(String[] args) throws Exception {
String url = "jdbc:mysql://192.168.29.116:3306/mydb"+"?useSSL=false"+"&allowPublicKeyRetrieval=false";
Connection conn = DriverManager.getConnection(
url, "testuser", "testpass"
);
System.out.println("Connected successfully");
conn.close();
}
}
In the above example, testuser uses caching_sha2_password. Also, we explicitly disabled SSL (useSSL=false). The driver attempts to fetch the public key. However, it fails due to the default security policy and throws an exception.
When we run the above code, we can see the expected error:
com.mysql.cj.exceptions.InvalidConnectionAttributeException:
Public Key Retrieval is not allowed
As a result, we can verify that the lab setup is working as expected.
4. Fixes for the Error
From the setup we already have, we can deduce several points:
- the exception doesn’t indicate wrong credentials
- the authentication method requires RSA encryption
- the driver refuses to fetch the public key automatically
So, even if the credentials are correct, the authentication method isn’t compatible.
There are several fixes for the error:
- allowing public key retrieval (development mode only)
- enabling SSL (secure way)
- changing authentication plugin (last resort)
However, the choice to use a fix depends on the environment.
5. Allow Public Key Retrieval (Development Only)
One of the quick fixes for this error is to explicitly enable the public key retrieval.
We can do this by adding the allowPublicKeyRetrieval=true string to the connection URL:
"jdbc:mysql://192.168.29.116:3306/mydb"+"?useSSL=false"+"&allowPublicKeyRetrieval=true";
Now, the driver can fetch the RSA public key from the server.
However, this method should only be used for local testing. Critically, for a production environment, it weakens security when used without SSL.
6. SSL Setup With Certificate Verification
If we configure SSL, we should get a more secure and permanent fix. Let’s see how to properly set up SSL on the MySQL server.
6.1. Enabling SSL on MySQL Server
First, we create a directory for MySQL SSL files:
$ sudo mkdir -p /etc/mysql/ssl
The above directory stores all certificates and private keys used by MySQL.
Next, we move to the new directory:
$ cd /etc/mysql/ssl
All files are now saved here, which helps protect sensitive keys.
MySQL needs a Certificate Authority (CA) to verify server certificates.
Let’s generate a CA private key:
$ sudo sh -c 'openssl genrsa 2048 > ca-key.pem'
The ca-key.pem is a private key and acts as the root of trust.
Next, we create a self-signed CA certificate using ca-key.pem:
$ sudo openssl req -new -x509 -nodes -days 3650 -key ca-key.pem -out ca.pem
In this case, the self-signed certificate ca.pem identifies the CA. Later, we also use it to sign the MySQL server certificate.
Next, we need two more keys:
- server-key.pem: private key for the server
- server-req.pem: key for certificate signing request (CSR)
Let’s create both of these keys:
$ sudo openssl req -newkey rsa:2048 -days 3650 -nodes \
-keyout server-key.pem -out server-req.pem \
-subj "/C=US/ST=CL/L=NewYork/CN=192.168.29.116"
Now, we can sign the server certificate using the CA:
$ sudo openssl x509 -req -in server-req.pem -days 3650 \
-CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem
Finally, we get a trusted server certificate, server-cert.pem. Clients can use the CA certificate to verify it.
Let’s secure the SSL keys:
$ sudo chmod 600 *.pem
$ sudo chown mysql:mysql *.pem
This way, only MySQL can access them.
6.2. Configure MySQL to Use SSL
After getting the certificates, we configure MySQL to use them. For this, we add the SSL key paths under the [mysqld] section of the MySQL configuration file.
Let’s open the mysqld.cnf file and make the changes:
$ sudo cat /etc/mysql/mysql.conf.d/mysqld.cnf
...
ssl-ca = /etc/mysql/ssl/ca.pem
ssl-cert = /etc/mysql/ssl/server-cert.pem
ssl-key = /etc/mysql/ssl/server-key.pem
...
To make the changes work, we restart MySQL:
$ sudo systemctl restart mysql
Let’s verify if SSL is active by checking the current SSL configuration inside MySQL:
mysql > SHOW VARIABLES LIKE '%ssl%';
Similarly, we can check the MySQL runtime status:
mysql > SHOW GLOBAL STATUS LIKE 'Ssl_%';
If we see have_ssl = YES and SSL files in the output, this means MySQL is running with SSL.
6.3. Copying the Server Certificate to the Client
For the Java client to work with the MySQL server over SSL, both sides need to trust each other. For this, we use the CA certificate.
So, we copy ca.pem from the server to the Java client machine. Specifically, let’s copy it to /tmp via scp:
$ sudo scp /etc/mysql/ssl/ca.pem [email protected]:/tmp/ca.pem
The file should go under /tmp on the Java client.
6.4. Create and Verify Java Truststore on Client
Java uses a truststore to validate SSL certificates. With a custom truststore, we can avoid modifying the system-wide JVM configuration.
Let’s create a new truststore and import the CA certificate, ca.pem, to it:
$ keytool -import -alias mysqlCA -keystore /tmp/mysql-truststore.jks -file /tmp/ca.pem \
-storepass changeit -noprompt
Thus, JVM can now trust the MySQL server during SSL handshakes.
Let’s verify the truststore:
$ keytool -list -v -keystore /tmp/mysql-truststore.jks -storepass changeit
The output lists the certificate alias, type, and CA details.
So, we can now use the Java truststore for SSL connections to MySQL.
6.5. Java Code With SSL
Once the truststore is ready, we update the Java code to use SSL:
System.setProperty("javax.net.ssl.trustStore", "/tmp/mysql-truststore.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
The properties point the JVM to the trusted certificates.
Finally, we update the JDBC connection URL:
String url = "jdbc:mysql://192.168.29.116:3306/mydb"+"?useSSL=true"+"&sslMode=VERIFY_CA"+"&allowPublicKeyRetrieval=true";
Each of the above parameters has a specific purpose:
- useSSL=true: turns on SSL
- sslMode=VERIFY_CA: checks the server certificate against the CA
- allowPublicKeyRetrieval=true: allows secure retrieval of the server public key when required
Finally, when we run the Java code, there should be no Public Retrieval error.
8. Changing the Authentication Plugin
We can also support older clients, where caching_sha2_password isn’t used. In this case, we switch the user to the older mysql_native_password authentication plugin.
For this, we use the ALTER command on the MySQL prompt:
mysql > ALTER USER 'testuser'@'%' IDENTIFIED WITH mysql_native_password BY 'testpass';
mysql > FLUSH PRIVILEGES;
As a result, we don’t need the RSA key exchange. However, this is a less secure way as it relies on an older authentication plugin.
9. Conclusion
In this article, we saw causes for the Public Key Retrieval is not allowed error and how to fix it.
Overall, using SSL to fix such errors should be considered the best option since it provides a more secure authentication method.

















