Java应用出现Public Key Retrieval is not allowed错误,是什么配置或代码问题导致的?
摘要:Java 应用报错 Public Key Retrieval is not allowed,原来是 caching_sha2_password 插件惹的祸!
问题现象
Java 应用在运行过程中突然报java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed错误。
开发童鞋表示不理解,毕竟应用没做任何变更,为什么会突然出现这个错误?
2025-03-3108:31:11- create connection SQLException, url: jdbc:mysql://10.0.1.86:3306/information_schema?useSSL=false, errorCode 0, state 08001
java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:110)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:828)
at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:448)
at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:241)
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:198)
at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1682)
at com.alibaba.druid.pool.DruidAbstractDataSource.createPhysicalConnection(DruidAbstractDataSource.java:1803)
at com.alibaba.druid.pool.DruidDataSource$CreateConnectionThread.run(DruidDataSource.java:2914)
...
问题原因
用户使用的密码认证插件是 caching_sha2_password 且 JDBC 连接串中指定了useSSL=false。
当碰到以下场景,就会出现上述报错:
第一次连接时。
数据库实例发生了重启。
服务端执行了 FLUSH PRIVILEGES 操作。
解决方法
解决方法有以下几种:
方案 1
将用户的密码认证插件调整为 mysql_native_password。不推荐该方法,因为 MySQL 9.0 移除了 mysql_native_password。
ALTERUSER'u1'@'%'IDENTIFIEDWITHmysql_native_passwordBY'MySQL@2025';
方案 2
在 JDBC 连接串中设置useSSL=true。推荐该方法,但开启 SSL 会有一定的性能开销。
如果既不想开启 SSL,又想避免 Public Key Retrieval is not allowed 错误,以下是两个可选的解决方案:
方案 3
在 JDBC 连接串中添加allowPublicKeyRetrieval=true。
该方法会自动从 MySQL 服务端获取 RSA 公钥,但这种方法有一定的安全风险,可能会受到中间人攻击。攻击者可以伪造 RSA 公钥,窃取用户密码。
方案 4
在 JDBC 连接串中指定serverRSAPublicKeyFile。
该方法需要将方案 3 中的公钥内容写到应用侧的一个本地文件中,具体步骤如下:
通过show status like 'Caching_sha2_password_rsa_public_key'命令或者从参数 caching_sha2_password_public_key_path(默认是 public_key.pem)指定的文件中获取公钥内容。
