现象:
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 连接字符串中允许公钥检索。推荐两种方案,方案一为最佳实践。

方案一:修改应用配置文件(推荐)

直接修改项目中的数据库配置文件,确保无论通过何种方式启动,配置都是完整且一致的。

  1. 如果是 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 问题,欢迎在评论区留言交流。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐