“handshake read exception”是mysql客户端在tls握手阶段读取服务器hello消息失败的io异常,常见于ssl配置错误、网络拦截或参数冲突。

MySQL连接报“Handshake read exception”是什么意思
这个错误不是MySQL服务端抛出的SQL错误,而是客户端在TCP连接建立后、进行SSL/TLS握手阶段失败时由JDBC(或其他客户端驱动)触发的底层IO异常。常见于Java应用用mysql-connector-java连接RDS或启用了SSL的MySQL实例时,本质是TLS协商卡在读取服务器Hello消息环节——可能根本没收到,也可能收到但格式/加密套件不匹配。
检查MySQL服务端是否真开启了SSL
别只看配置文件里有没有ssl_mode=REQUIRED,得确认服务端实际加载了证书且监听了SSL连接:
- 登录MySQL执行:
SHOW VARIABLES LIKE '%ssl%';,重点看have_ssl是否为YES,ssl_ca/ssl_cert/ssl_key路径是否真实存在且可读 - 执行:
SHOW STATUS LIKE 'Ssl%';,如果所有值都是空或0,说明当前没有活跃SSL连接,甚至可能证书加载失败(比如私钥密码不对、权限为777) - RDS用户注意:AWS/Aliyun默认不强制SSL,需在控制台显式开启“SSL加密连接”,并下载对应CA证书;仅修改参数组里的
require_secure_transport=ON不够,客户端不配CA照样连不上
JDBC URL里sslMode和useSSL参数怎么设才不冲突
新版mysql-connector-java 8.0+已废弃useSSL=true,改用sslMode,但很多项目还混着写,导致驱动行为异常:
- ❌ 错误写法:
jdbc:mysql://x.x.x.x:3306/db?useSSL=true&sslMode=REQUIRED—— 驱动会忽略sslMode,按旧逻辑走,可能因JDK版本差异直接拒绝握手 - ✅ 正确写法(推荐):
jdbc:mysql://x.x.x.x:3306/db?sslMode=REQUIRED&serverTimezone=UTC,不带useSSL - 如果服务端没配SSL但客户端强制要求,会报
Could not connect to x.x.x.x:3306 : Could not connect to x.x.x.x:3306 : SSL connection failed,此时要确认服务端状态,而不是调客户端参数
云厂商安全组和网络ACL常被忽略的拦截点
“Handshake read exception”看着像加密问题,但大概率是网络层就断了——TLS握手需要完整双向通信,任何中间设备丢包都会表现为“读超时”:
- 检查安全组入方向是否放行了MySQL端口(如3306),且**出方向也必须放行**(客户端要回包给服务端完成握手)
- 阿里云/Native VPC中,若启用“网络ACL”,它比安全组更底层,会默认拒绝所有流量,必须显式添加允许3306出入规则
- 企业内网常见情况:出口代理或防火墙主动终止TLS连接(如做HTTPS解密),此时客户端看到的是服务端IP,实际中间设备伪造了证书,导致握手失败;可抓包确认SYN→SYN-ACK→ACK正常,但后续Client Hello发出去后没收到Server Hello
真正棘手的是混合场景:服务端证书过期 + 安全组出方向未放行 + JDBC URL同时写了useSSL和sslMode——错误日志只会笼统报“Handshake read exception”,得逐层排除,不能只盯SSL配置。











