结论是SSL握手协商失败,核心在于客户端启用SSL而服务端未配置或未强制SSL,导致不匹配报错;MySQL 5.7.28+默认尝试SSL协商,若服务端无证书或未禁用SSL即拒绝握手;JDBC加useSSL=false可能因参数名错误、分隔符缺失、驱动版本差异或Spring Boot校验增强而失效;根治方式是在mysqld配置中添加skip_ssl并重启,确保have_ssl为DISABLED。

直接说结论:这不是密码或网络问题,而是SSL握手协商失败,核心在客户端是否启用SSL、服务端是否强制要求SSL,二者不匹配就报 ERROR 1043 (08S01) 或日志里反复出现 [Note] Bad handshake。
为什么5.7.28+版本突然报Bad handshake?
MySQL从5.7.28开始,默认行为变了:即使你没配SSL,JDBC驱动(如 mysql-connector-java 8.x)也会尝试协商SSL连接;而服务端若没配证书或未显式禁用SSL,就会拒绝握手——不是“连不上”,是“连上了但聊不拢”。
典型现象:Navicat 能连(它默认关SSL),但Java项目启动失败,报 Communications link failure + Bad handshake;或者MySQL错误日志里高频刷出 [Note] Bad handshake,但没其他ERROR。
JDBC连接串加 useSSL=false 为什么有时无效?
常见坑点:
• 参数名写错成 userSSL=false(少了个 s),驱动直接忽略该配置
• URL里已有多个参数,漏了 & 分隔,比如写成 ?useUnicode=true&useSSL=falsecharacterEncoding=utf8(characterEncoding 前缺 &)
• 使用了旧版驱动(如 mysql-connector-java 5.1.x),它认 useSSL,但新版(8.0+)更倾向用 enabledTLSProtocols 或 allowPublicKeyRetrieval=true 配合 useSSL=false
• Spring Boot 2.4+ 默认启用SSL校验,光加 useSSL=false 不够,还得加 allowPublicKeyRetrieval=true,否则抛 SSLHandshakeException
服务端禁用SSL比客户端绕过更彻底
改客户端只是“躲开问题”,改服务端才是根治。操作很简单:
• 找到MySQL配置文件(Linux是 /etc/my.cnf 或 /etc/mysql/my.cnf,Windows是 my.ini)
• 在 [mysqld] 段落下添加一行:skip_ssl
• 重启MySQL服务(systemctl restart mysqld 或 Windows 服务管理器里重启)
注意:不要加 ssl=0 或 ssl_disabled=1,这些不是标准配置项;skip_ssl 是唯一被广泛验证有效的写法。改完后执行 show variables like '%ssl%';,确认 have_ssl 和 have_openssl 都返回 DISABLED。
别忽略端口冲突和多实例干扰
有些情况下,Bad handshake 是假象:
• 本地同时装了MySQL 5.7 和 8.0,服务名/端口/数据目录混了,实际连的是另一个没配好SSL的实例
• netstat -ano | findstr :3306 发现PID不是 mysqld.exe,而是其他进程(比如某个Node.js服务或旧版MySQL残留)占着端口
• Windows下用命令行直接执行 mysqld --console 启动,会绕过服务配置,导致 skip_ssl 不生效
真正要检查的,是当前正在响应请求的那个MySQL进程,到底读的是哪个配置文件——用 SELECT @@config_file;(MySQL 8.0.22+)或查启动参数 ps aux | grep mysqld 确认。


















