1. 问题现象与背景解析
当Java应用通过JDBC连接MySQL 8.0及以上版本时,突然出现Public Key Retrieval is not allowed错误,这种情况通常发生在以下场景:
- 首次建立连接时
- MySQL服务重启后
- 执行
FLUSH PRIVILEGES命令后 - 连接参数中明确设置了
useSSL=false
典型错误信息如下:
java复制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.ConnectionImpl.createNewIO(ConnectionImpl.java:828)
这个问题的根源在于MySQL 8.0默认启用了新的认证插件caching_sha2_password,该插件在安全机制上与旧版的mysql_native_password有本质区别。当SSL加密未启用时,插件需要获取服务端的RSA公钥来加密密码,但JDBC驱动出于安全考虑默认禁止了此行为。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 认证机制深度剖析
2.1 caching_sha2_password工作原理
MySQL 8.0引入的caching_sha2_password插件采用双层缓存机制:
- 快速认证路径:服务端维护一个密码哈希缓存(m_cache),存储
SHA256(SHA256(password))值。当缓存命中时,客户端只需发送基于随机数生成的scramble响应即可完成认证。 - 完整认证路径:当缓存未命中时,客户端必须发送明文密码。此时安全策略要求:
- 通过SSL加密通道传输
- 或使用RSA公钥加密传输
认证流程时序图:
code复制客户端 服务端
| ---- Handshake Packet ---> |
| <--- Auth Switch Request --|
| ---- Scramble Response --->|
| <- Perform Full Auth Req -|
| ---- Encrypted Password -->|
| <----- Auth OK/Error -----|
2.2 公钥获取的安全限制
当同时满足以下条件时触发该错误:
- 使用
caching_sha2_password插件 - 连接参数设置
useSSL=false - 未配置
allowPublicKeyRetrieval=true - 未指定
serverRSAPublicKeyFile
MySQL服务端的公钥存储位置:
- 动态获取:
SHOW STATUS LIKE 'Caching_sha2_password_rsa_public_key' - 静态文件:
caching_sha2_password_public_key_path参数指定(默认public_key.pem)
3. 解决方案对比实施
3.1 方案一:启用SSL加密(推荐)
在连接字符串中添加:
code复制jdbc:mysql://host:3306/db?useSSL=true&requireSSL=true
优点:
- 符合安全最佳实践
- 避免密码明文传输
- 支持所有MySQL版本
缺点:
- 约5-10%的性能开销
- 需要配置证书(生产环境建议使用CA签名证书)
3.2 方案二:允许公钥获取
临时解决方案(开发环境适用):
code复制jdbc:mysql://host:3306/db?allowPublicKeyRetrieval=true
安全风险:
- 可能遭受MITM攻击
- 公钥传输未加密
- 不符合PCI DSS等安全标准
3.3 方案三:指定公钥文件
高级安全配置:
- 获取服务端公钥:
sql复制SHOW STATUS LIKE 'Caching_sha2_password_rsa_public_key'; - 保存为本地文件(如
/opt/mysql_public_key.pem) - 连接配置:
code复制
jdbc:mysql://host:3306/db?serverRSAPublicKeyFile=/opt/mysql_public_key.pem
适用场景:
- 禁用SSL的内网环境
- 需要固定公钥的容器化部署
3.4 方案四:改用传统认证(不推荐)
修改用户认证插件:
sql复制ALTER USER 'username'@'%' IDENTIFIED WITH mysql_native_password BY 'password';
缺点:
- MySQL 8.4+已移除该插件
- 安全性较低(SHA1哈希)
- 无法使用密码轮换等新特性
4. 生产环境最佳实践
4.1 高可用架构配置
对于MySQL集群环境,建议采用统一配置:
- 主从节点使用相同密钥对:
ini复制[mysqld] caching_sha2_password_private_key_path=/etc/mysql/key.pem caching_sha2_password_public_key_path=/etc/mysql/key.pub - 应用连接串示例:
code复制jdbc:mysql://cluster-host:3306/db?useSSL=true&serverRSAPublicKeyFile=/app/conf/mysql_key.pub
4.2 连接池特殊配置
Druid连接池示例配置:
xml复制<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url"
value="jdbc:mysql://host:3306/db?useSSL=true&serverRSAPublicKeyFile=/conf/key.pub"/>
<property name="connectionInitSqls" value="SET SESSION query_cache_type=OFF"/>
</bean>
注意事项:
- 避免连接验证时触发公钥获取
- 设置合理的validationQuery超时时间
- 主从切换后需要重建连接池
4.3 安全审计建议
- 监控日志中的异常连接
- 定期轮换RSA密钥对:
bash复制openssl genrsa -out private_key.pem 2048 openssl rsa -in private_key.pem -pubout -out public_key.pem - 使用MySQL企业审计插件记录认证事件
5. 疑难问题排查指南
5.1 典型错误场景
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 连接时断时续 | 主从切换导致公钥变化 | 配置集群统一公钥 |
| 部分客户端报错 | JDBC驱动版本不一致 | 统一使用8.0.23+版本 |
| 仅特定用户失败 | 用户插件配置冲突 | 检查mysql.user表plugin字段 |
5.2 诊断步骤
- 确认认证插件:
sql复制SELECT plugin FROM mysql.user WHERE user='username'; - 检查SSL状态:
sql复制SHOW STATUS LIKE 'Ssl_cipher'; - 验证公钥有效性:
bash复制openssl rsa -pubin -in key.pub -text -noout
5.3 性能调优参数
对于高并发场景建议调整:
ini复制[mysqld]
caching_sha2_password_auto_generate_rsa_keys=OFF
caching_sha2_password_private_key_path=/etc/mysql/ssl/private.pem
caching_sha2_password_public_key_path=/etc/mysql/ssl/public.pem
ssl_cert=/etc/mysql/ssl/server-cert.pem
ssl_key=/etc/mysql/ssl/server-key.pem
6. 版本兼容性矩阵
| MySQL版本 | JDBC驱动 | 推荐配置 |
|---|---|---|
| 5.7及以下 | 5.1.x | mysql_native_password |
| 8.0-8.3 | 8.0.x | caching_sha2_password+SSL |
| 8.4+ | 8.0.23+ | 必须使用caching_sha2_password |
迁移注意事项:
- 升级前备份
mysql.user表 - 测试所有应用的连接兼容性
- 准备回滚方案:
sql复制ALTER USER 'app_user'@'%' IDENTIFIED WITH mysql_native_password BY 'old_password';
在实际运维中,我曾遇到一个典型案例:某金融系统升级MySQL 8.0后,夜间批处理作业频繁失败。最终发现是连接池未配置serverRSAPublicKeyFile参数,且作业服务器与数据库的SSL证书校验失败。解决方案是统一采用物理公钥文件方式,既保证了安全性,又避免了SSL证书管理的复杂性。
