问题现象
SpringBoot + HikariCP 连接 MySQL5.6,定时任务获取数据库连接时报错,核心堆栈:
Caused by: javax.net.ssl.SSLHandshakeException: (certificate_unknown) java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
上层异常:
org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction
特征:Hikari 持续重试创建连接池失败,定时任务反复抛出异常;网络、端口、账号密码本身是通的,问题卡在 SSL/TLS 握手阶段。
很多人第一反应以为是网络不通,实际是证书信任链校验失败。
根因分析
- MySQL 5.6 默认的 SSL 证书是 MySQL 内部自生成的自签名证书,不存在合法 CA 信任链;
mysql-connector-java 8.x驱动默认主动发起 SSL 协商,和老版本驱动行为不一样;- 哪怕你的 MySQL5.6 根本没启用 SSL,驱动依然会尝试走 TLS 握手;握手之后拿到自签证书,JDK 默认信任库(cacerts)里面没有这个根证书,校验直接失败;
- 注意区分:MySQL8 是强制 SSL,MySQL5.6 只是支持 SSL,默认不强制开启,坑来自新版驱动的默认行为,不是数据库强制要求加密。
执行 SQL 查看 MySQL5.6 SSL 状态:
show variables like '%ssl%';
have_ssl = DISABLED:数据库 SSL 是关闭状态,根本没有启用加密传输,最优方案:直接关闭驱动 SSL 协商have_ssl = YES:数据库开启了 SSL 支持,可以握手
三种解决方案(按推荐优先级排序)
方案一:内网环境首选,直接关闭 SSL 协商(推荐绝大多数场景)
MySQL5.6 内网业务,没有传输加密需求,直接在连接串增加 useSSL=false,驱动不再发起 TLS 握手,从根源规避证书校验问题。
application.properties
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb?useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
application.yml
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/testdb?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 10
补充说明:网上很多文档说
useSSL参数已经废弃,这个说法主要针对 MySQL8;MySQL5.6 + 8.x 驱动场景,useSSL=false 完全可用,是最稳妥方案。
方案二:需要 SSL 加密传输,临时关闭证书校验(仅应急,公网不推荐)
业务要求走 SSL 加密,但暂时不方便导入证书,可以关闭服务端证书校验,存在中间人劫持风险,仅限临时调试、内网测试,禁止公网生产长期使用。
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb?useSSL=true&verifyServerCertificate=false&serverTimezone=Asia/Shanghai
方案三:正式安全方案,将 MySQL 自签 CA 证书导入 JDK 信任库(公网加密场景)
MySQL5.6 的证书默认存放路径:/var/lib/mysql/,找到 ca.pem 根证书文件。
- 导入证书到 JDK 的 cacerts 信任库
keytool -importcert -alias mysql56-ca -file ca.pem -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit
注意:JDK9 + 模块化版本,cacerts 路径有变化;容器化部署建议在 Dockerfile 构建阶段导入证书,不要在运行容器里手动操作。
- 连接串正常开启 SSL,不关闭校验
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/testdb?useSSL=true&serverTimezone=Asia/Shanghai
重要避坑清单(MySQL5.6 + 8.x 驱动专属)
- 不要随意添加
allowPublicKeyRetrieval=true:该参数是解决public key retrieval is not allowed报错,和本次 SSL 证书链报错无关,开启后有安全隐患; - 认证插件:MySQL5.6 使用
mysql_native_password,不支持 caching_sha2_password,这是另外一类密码报错,和 SSL 证书问题区分开; serverTimezone=Asia/Shanghai是 8.x 驱动强制要求,MySQL5.6 本身不识别该参数,是驱动侧用来处理时区转换,不能省略;- 先验证基础连通性:在应用所在服务器用原生 mysql 客户端连接数据库,确认 IP、端口、防火墙、账号白名单没问题,排除基础网络问题;
- Hikari 池报错特征:反复打印
HikariPool-1 - Starting...,就是持续新建连接失败,连接池无法就绪,所有依赖 DB 的业务(定时任务、接口)全部异常。
排查步骤总结
- 登录 MySQL 执行
show variables like '%ssl%',确认数据库 SSL 状态; - have_ssl=DISABLED / 内网无加密需求 → 直接 useSSL=false(首选);
- have_ssl=YES,但是不需要严格证书校验 → 临时
verifyServerCertificate=false; - 公网、合规要求 SSL 加密 → 导出 ca.pem,导入 JDK 信任库;
- 修改配置后重启应用,观察 Hikari 是否成功初始化连接池。
小结
这个坑本质是新版 JDBC 驱动和老旧 MySQL5.6 的默认行为不匹配。很多人升级驱动后踩坑,优先不要上来就关闭证书校验,内网场景直接关掉 SSL 协商是成本最低、最稳定的解法。
正文完
可以使用微信扫码关注公众号(ID:xzluomor)