【实战解决】MySQL 8.0 + Supervisor + Java:命令行正常但守护进程报 “Public Key Retrieval is not allowed“ 终极方案
现象:
1、使用 nohup java -jar … 命令行启动服务完全正常,但配置 Supervisor 启动后,服务运行几秒便自动退出。
2、查看日志发现报错:com.mysql.cj.exceptions.UnableToConnectException: Public Key Retrieval is not allowed。
环境:MySQL 8.0 + JDK 17 + Ubuntu (ARM64) + Supervisor。
一、问题复现与环境
1. 环境信息
操作系统:Ubuntu Server (ARM64 架构)
数据库:MySQL 8.0+ (默认认证插件为 caching_sha2_password)
运行方式:Supervisor 守护进程
JDK 版本:OpenJDK 17
2. 异常日志
Supervisor 管理的日志文件 (/data/javaweb/logs/media.log) 中频繁出现以下堆栈:
Caused by: com.zaxxer.hikari.pool.HikariPool$PoolInitializationException: Failed to initialize pool: Public Key Retrieval is not allowed
at com.zaxxer.hikari.pool.HikariPool.throwPoolInitializationException(HikariPool.java:596)
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:582)
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115)
at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:81)
com.mysql.cj.exceptions.UnableToConnectException: Public Key Retrieval is not allowed
at com.mysql.cj.protocol.a.authentication.CachingSha2PasswordPlugin.nextAuthenticationStep(...)
...
3. 奇怪现象
1)服务正常运行,连接数据库无误
nohup /usr/local/jdk/bin/java -jar media.jar >/dev/null 2>&1 &
2)Supervisor 启动失败:
配置好 .conf 文件后,执行 supervisorctl start media,状态显示 RUNNING,但几秒钟后变为 STOPPED 或 FATAL,日志报上述公钥错误。
二、原因深度分析
为什么同样的 Jar 包,命令行能跑,Supervisor 却报错?核心原因在于 MySQL 8.0 的安全机制 与 进程启动环境的差异。
1. MySQL 8.0 的认证机制变更
1)MySQL 8.0 默认将密码加密插件从 mysql_native_password 升级为 caching_sha2_password。
2)当客户端(Java Driver)连接时,如果本地没有缓存服务器的公钥,驱动需要向服务器请求公钥以加密密码。
3)安全默认值:出于防止中间人攻击的考虑,MySQL Connector/J 驱动默认配置 allowPublicKeyRetrieval=false。即:禁止自动获取公钥。
2. 为什么命令行能成功?
这通常是由于隐式的环境差异导致的:
1)配置文件覆盖:可能在命令行启动时,你无意中加载了外部的配置文件(如 --spring.config.location=…),或者当前用户的环境变量中注入了特定的 JDBC URL 参数。
2)历史缓存:如果是同一台机器,之前的命令行连接可能已经建立了某种会话缓存(较少见,但在特定驱动版本下可能发生)。
3)最可能的原因:你的 application.properties 或 application.yml 中其实并没有配置完整的 JDBC URL,而是依赖了某些默认值或环境变量。而在 Supervisor 模式下,它作为一个纯净的守护进程,不会加载用户的 .bashrc 或 .profile,导致读取到的 JDBC URL 是“残缺”的(缺少了关键参数),从而触发了默认的 false 策略。
3. 为什么 Supervisor 会报错?
Supervisor 启动的进程是一个标准的后台服务,它严格读取 Jar 包内部或指定目录下的默认配置文件。由于配置文件中缺少 allowPublicKeyRetrieval=true,驱动严格遵守安全规范,拒绝连接并抛出异常,导致 Spring Boot 启动失败,进程退出。
三、解决方案
要彻底解决此问题,必须显式地在 JDBC 连接字符串中允许公钥检索。推荐两种方案,方案一为最佳实践。
方案一:修改应用配置文件(推荐)
直接修改项目中的数据库配置文件,确保无论通过何种方式启动,配置都是完整且一致的。
- 如果是 application.properties
找到 spring.datasource.url,追加参数 allowPublicKeyRetrieval=true 和 useSSL=false(除非你有明确的 SSL 证书需求,否则开发/内网环境建议关闭 SSL 以减少握手问题)。
# 修改前
spring.datasource.url=jdbc:mysql://192.168.1.100:3306/mydb?serverTimezone=Asia/Shanghai&characterEncoding=utf-8
# 修改后 (注意 & 符号连接)
spring.datasource.url=jdbc:mysql://192.168.1.100:3306/mydb?serverTimezone=Asia/Shanghai&characterEncoding=utf-8&allowPublicKeyRetrieval=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=yourpassword
2、如果是 application.yml
spring:
datasource:
url: jdbc:mysql://192.168.1.100:3306/mydb?serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false
username: root
password: yourpassword
操作步骤:
1)修改配置文件。
2)重新打包 Jar 或确保外部配置目录文件已更新。
3)重启 Supervisor:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart media
方案二:在 Supervisor 配置中注入参数(无需改代码)
1)如果你无法修改配置文件,或者希望针对生产环境和测试环境有不同的连接策略,可以在 Supervisor 的 command 行中通过 Spring Boot 的参数覆盖机制注入。
2)编辑 /etc/supervisor/conf.d/media.conf
[program:media]
directory=/data/javaweb
# 关键点:在命令末尾追加 --spring.datasource.url=...
# 注意:URL 中包含 & 符号,建议使用单引号包裹整个参数值,防止 Shell 解析错误
command=/usr/local/jdk/bin/java -jar media.jar --spring.datasource.url='jdbc:mysql://192.168.1.100:3306/mydb?serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false'
autostart=true
autorestart=true
startretries=3
user=root
priority=100
stopsignal=INT
redirect_stderr=true
stdout_logfile=/data/javaweb/logs/media.log
stdout_logfile_maxbytes=300MB
stopasgroup=false
killasgroup=false
重载配置
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl restart media
四、验证与监控
配置完成后,务必进行以下验证:
1.检查状态:
sudo supervisorctl status media
# 期望输出:media RUNNING pid 12345, uptime 0:05:10
2.查看实时日志:
tail -f /data/javaweb/logs/media.log
3.模拟重启测试:
sudo reboot
# 服务器重启后,再次检查服务是否自动拉起
sudo supervisorctl status
五、总结与避坑指南
1)MySQL 8.0 特性:只要升级到 MySQL 8.0+,务必在 JDBC URL 中显式添加 allowPublicKeyRetrieval=true,这是新版本的默认安全策略,不是 Bug。
2)环境一致性:不要依赖“命令行能跑”就认为配置没问题。Supervisor、Systemd、Docker 等守护进程的启动环境与交互式 Shell 不同,它们通常不加载用户的环境变量。显式配置永远优于隐式依赖。
3)SSL 问题:如果添加了 allowPublicKeyRetrieval=true 后报 SSL 相关错误,请同时加上 useSSL=false。在生产环境如果需要 SSL,请正确配置信任库,而不是简单关闭。
4)ARM64 架构:本文案例发生在 ARM64 服务器,但该问题是 MySQL 驱动层面的,与 CPU 架构无关,x86_64 服务器同样会遇到。
觉得有用请点赞收藏!👍
如果在部署过程中遇到其他 Supervisor 或 MySQL 问题,欢迎在评论区留言交流。
更多推荐




所有评论(0)