必须启用require_secure_transport=on且服务端ssl真正可用(have_ssl=yes、证书路径正确可读、无selinux拦截),客户端还需显式指定--ssl-mode=required等参数,否则连接被拒。

MySQL 8.0+ 要真正强制所有远程连接走加密通道,光设 REQUIRE SSL 用户远远不够;必须开启 require_secure_transport=ON,且服务端 SSL 实际可用——否则客户端连不上不是权限问题,是根本没握手能力。
确认 MySQL 服务端 SSL 已真正启用
很多“配置完连不上”的问题,根源是 have_ssl 显示 DISABLED 或空值,说明 OpenSSL 模块压根没加载或证书路径失效。
- 执行
SHOW VARIABLES LIKE 'have_ssl';,结果必须是YES;若为DISABLED,跳过后续所有步骤都白搭 - 检查
ssl_ca、ssl_cert、ssl_key三个变量是否非空,且路径是绝对路径(如/etc/mysql/ssl/ca.pem),不能是相对路径或软链接 - Linux 下常见拦截:SELinux 或 AppArmor 阻止
mysqld读取证书文件,临时执行setenforce 0测试能快速定位 - 证书文件权限需严格(如
600),MySQL 进程用户(通常是mysql)必须有读权限
开启全局强制加密开关 require_secure_transport
这个参数才是“一刀切”禁止明文连接的核心。它只影响 TCP 连接(Unix socket 如 localhost 默认绕过),所以生产环境务必配合网络层控制。
- 运行时启用:
SET PERSIST require_secure_transport = ON;(推荐,自动写入持久化配置) - 配置文件启用:在
[mysqld]段添加require_secure_transport=ON,然后重启mysqld - 注意:该设置生效后,所有未使用 TLS 的 TCP 连接(包括 root@127.0.0.1)都会被拒绝,错误提示类似
Access denied for user,但实际是连接被服务端直接终止 - 验证是否生效:
SELECT @@GLOBAL.require_secure_transport;返回1
客户端连接必须显式声明 SSL 模式
即使服务端开了 require_secure_transport,客户端不主动发起 TLS 握手,照样被拒——这不是认证失败,是协议层被拦在门外。
- 命令行连接必须加
--ssl-mode=REQUIRED,例如:mysql -u secure_user -h 192.168.1.100 -p --ssl-mode=REQUIRED - JDBC URL 必须显式启用并指定协议:
?useSSL=true&requireSSL=true&enabledTLSProtocols=TLSv1.2;旧版驱动用usessl=true无效 - PHP mysqli 需传入
MYSQLI_CLIENT_SSL标志,PDO 则要在 DSN 中加sslmode=require或完整证书路径 - 避免用
--ssl-mode=VERIFY_IDENTITY配自签名证书:客户端会校验 CN 域名,而自签证书 CN 通常为localhost,与真实 IP 或域名不匹配,直接报错
验证连接是否真走加密通道
别只信客户端参数,要从服务端会话状态看真实 cipher。
- 登录后执行:
SHOW SESSION STATUS LIKE 'Ssl_cipher';,有非空返回值(如TLS_AES_256_GCM_SHA384)才表示当前连接已加密 - 执行
\s或STATUS,输出中 “SSL” 行显示协议版本和 cipher,若为Not in use,说明连接仍是明文 - 注意:同一用户可能同时存在多个连接,部分旧连接缓存了非 SSL 权限,执行
FLUSH PRIVILEGES;可清空权限缓存,但更可靠的是断开重连 - 如果应用连的是
localhost,默认走 Unix socket,不受require_secure_transport约束;改用127.0.0.1强制走 TCP 才能触发校验
最常被忽略的点:证书路径权限、SELinux/AppArmor 拦截、客户端未显式启用 SSL 模式——这三者任一缺失,require_secure_transport=ON 就形同虚设。服务端配得再严,只要握手阶段失败,连接就断在第一步。











