记一次 Druid 连接 MySQL 报 Communications link failure 的排查过程

问题现象

Druid 连接池启动时报错:

复制代码
com.mysql.cj.jdbc.exceptions.CommunicationsException: 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.
    at com.mysql.cj.protocol.a.NativeProtocol.negotiateSSLConnection(NativeProtocol.java:361)
    ...
Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol 
(protocol is disabled or cipher suites are in

连接地址是 jdbc:mysql://127.0.0.1:3306/k_k,MySQL 就在本机。

排查过程

1. 先排除基础问题

确认 MySQL 服务在运行、端口 3306 可通,排除服务没启动、防火墙拦截等常见原因。

2. 定位到 SSL 握手阶段

堆栈里最关键的一行是:

复制代码
at com.mysql.cj.protocol.a.NativeProtocol.negotiateSSLConnection(NativeProtocol.java:361)

说明 TCP 连接已经建立,问题出在 SSL 握手阶段,而不是网络不通。

3. 检查 MySQL 的 TLS 配置

sql 复制代码
SHOW VARIABLES LIKE 'tls_version';

结果:

复制代码
TLSv1,TLSv1.1,TLSv1.2

MySQL 支持 TLSv1.2,但同时也启用了已被淘汰的 TLSv1 和 TLSv1.1。

4. 获取 CA 证书

MySQL 启用 SSL 后,数据目录下会生成一组证书文件。先找到数据目录:

sql 复制代码
SHOW VARIABLES LIKE 'datadir';

在数据目录里找到 ca.pem,这就是服务端的 CA 证书。

5. 将 CA 证书导入 Java 信任库

使用 JDK 自带的 keytool:

bash 复制代码
/www/server/java/jdk1.8.0_371/bin/keytool -importcert \
  -alias MySQLCACert \
  -file /www/server/data/ca.pem \
  -keystore truststore.jks \
  -storepass 你的密码

生成的 truststore.jks 位于执行命令时的当前目录。

6. 在 JDBC URL 中配置信任库

复制代码
jdbc:mysql://127.0.0.1:3306/k_k?sslMode=VERIFY_CA&trustCertificateKeyStoreUrl=file:/路径/truststore.jks&trustCertificateKeyStorePassword=你的密码

重新启动后,仍然报同样的错。

真正的原因

这是 MySQL Connector/J 8.0.18 及更早版本的一个已知设计问题:

  • Connector/J 8.0.16 出于兼容旧版 MySQL(yaSSL 编译)的考虑,默认不启用 TLSv1.2,只尝试用 TLSv1/TLSv1.1 协商。
  • JDK 8u371 默认禁用了 TLSv1 和 TLSv1.1 这两个不安全的旧协议。

双方在"能用哪个协议"上谈不拢,SSL 握手直接失败。

解决方案

在 JDBC URL 中显式指定 TLS 协议版本:

复制代码
jdbc:mysql://127.0.0.1:3306/k_k?sslMode=VERIFY_CA&trustCertificateKeyStoreUrl=file:/路径/truststore.jks&trustCertificateKeyStorePassword=你的密码&enabledTLSProtocols=TLSv1.2

关键是 enabledTLSProtocols=TLSv1.2,它强制驱动使用 TLSv1.2,打破协议僵局。加上后连接正常。

几个容易踩的坑

  • ssl_cipher 查询为空是正常的,MySQL 8.0 的密码套件由底层 OpenSSL 管理,不再通过该变量显式列出。
  • ssl_ca 只返回 ca.pem 而非完整路径也是正常的 ,该变量存储的是配置文件里填写的值,要拿绝对路径得查 datadir。
  • keytool 命令找不到 ,是因为它不在系统 PATH 里,需要用 JDK bin 目录下的绝对路径执行。

后续可以改进的地方

  1. 升级驱动 :Connector/J 8.0.19 及以上版本已修复默认不启用 TLSv1.2 的问题,升级后可以去掉 enabledTLSProtocols 参数。
  2. 清理 MySQL 旧协议 :在 my.cnf 的 [mysqld] 段加上 tls_version=TLSv1.2,TLSv1.3,重启 MySQL,让服务端也彻底禁用旧协议,安全性更好。

最终可用配置

复制代码
jdbc:mysql://127.0.0.1:3306/k_k?sslMode=VERIFY_CA&trustCertificateKeyStoreUrl=file:/路径/truststore.jks&trustCertificateKeyStorePassword=你的密码&enabledTLSProtocols=TLSv1.2

版本信息:

  • MySQL Connector/J 8.0.16
  • Druid 1.1.18
  • JDK 1.8.0_371
复制代码
相关推荐
星恒随风3 小时前
MySQL 从零入门(六):复合查询详解——多表查询、自连接、子查询与 UNION
linux·服务器·数据库·mysql
无奈笑天下4 小时前
银河麒麟上lsblk命令教程详解
linux·运维·服务器·数据库
xiaoye-duck6 小时前
《C++ 项目:手写大模型接入 SDK》会话模块整合:内存 SessionManager 与 DataManager 持久化联动
开发语言·数据库·c++·语言模型
AllData公司负责人6 小时前
AI大模型数据开发底座系列说明书:AllData集成DB-GPT开源项目建设 AI 多模态分析底座,涵盖模态解析/智能大屏/MCP 扩展!
大数据·数据库·人工智能·gpt·数据采集·数据接入·模态解析
隔窗听雨眠7 小时前
MySQL进程卡死的定位思路与恢复实践
mysql·故障排查·数据库运维
2601_967987377 小时前
Sqlite参考手册
数据库·python·sqlite·api·教程
隔窗听雨眠7 小时前
Oracle日志体系分层结构与故障定位路径
数据库·oracle·故障排查
为思念酝酿的痛7 小时前
C语言操作MySQL
数据库·mysql
ShineWinsu8 小时前
对于Qt:QTabWidget常见属性的解析
开发语言·数据库·c++·qt·浏览器·qtabwidget·标签页
星恒随风18 小时前
MySQL 从零入门(五):MySQL 内置函数详解——日期、字符串、数学函数与实战案例
linux·数据库·笔记·sql·mysql