have_ssl必须为yes,否则ssl配置无效;需执行show variables like 'have_ssl'确认,再查ssl_ca、ssl_cert、ssl_key路径是否为非空绝对路径,且文件权限正确、属主为mysql用户。

have_ssl 必须为 YES,否则所有后续配置都无效——连不上、报错像权限问题、REQUIRE SSL 不生效,根源都在这一步没过。
确认 MySQL 服务端真正启用了 SSL
很多“配了连不上”的问题,其实根本没走到用户权限校验那步,SSL 握手压根没启动。
登录 MySQL 后执行:SHOW VARIABLES LIKE 'have_ssl'; —— 结果必须是 YES;若为 DISABLED 或空值,说明 OpenSSL 模块未加载或配置被忽略。
再查:SHOW VARIABLES LIKE 'ssl_%';,重点确认:
-
ssl_ca、ssl_cert、ssl_key三项值必须是非空绝对路径(如/var/lib/mysql/ca.pem),不能是OFF、空字符串或相对路径 - 证书文件属主必须是
mysql用户,server-key.pem权限必须为600 - SELinux/AppArmor 可能静默拦截读取,临时执行
setenforce 0测试可快速验证 - 配置必须写在
[mysqld]段,写进[client]段对服务端完全无效
生成并验证证书路径与权限
MySQL 对证书路径和权限极其敏感,错一个就静默失败。
推荐用内置工具(MySQL 8.0+):mysql_ssl_rsa_setup --datadir=/var/lib/mysql --uid=mysql
执行前确保:
- 进入数据目录:
cd /var/lib/mysql,并运行chown mysql:mysql . - 生成后检查关键文件:
ca.pem、server-cert.pem、server-key.pem - 验证权限:
sudo -u mysql ls -l /var/lib/mysql/server-key.pem—— 必须显示-rw------- - 所有路径必须以
/开头,./ca.pem或~/ca.pem会被忽略
别把证书放
/tmp、/home 或 root 家目录下——MySQL 进程默认无权读取。
创建或修改用户时显式声明 REQUIRE SSL
这是账户级强制策略,不是全局开关,且只在服务端 SSL 已启用的前提下才生效。
- 新建用户:
CREATE USER 'appuser'@'10.0.2.%' IDENTIFIED BY 'p4ssw0rd' REQUIRE SSL; - 已有用户(MySQL ≥ 8.0.22):
ALTER USER 'appuser'@'10.0.2.%' REQUIRE SSL; - 执行后必须
FLUSH PRIVILEGES;,否则旧连接可能仍缓存旧权限状态 - 验证是否生效:
SELECT user, host, ssl_type FROM mysql.user WHERE user = 'appuser';,ssl_type应为ANY - 注意:
REQUIRE SSL只校验连接是否加密,不校验客户端证书;别误用REQUIRE X509——后者要求客户端提供有效证书,部署复杂得多
客户端必须主动发起 TLS 握手才能成功连接
服务端设了 REQUIRE SSL,客户端不声明意图,连接会在协议层被直接终止,错误常是 Access denied for user,但这不是认证失败,而是 TLS 握手根本没开始。
- 命令行测试:
mysql -u appuser -h 192.168.1.100 -p --ssl-mode=REQUIRED
(--ssl-mode=VERIFY_IDENTITY对自签名证书大概率失败,因 CN 通常为localhost,不匹配 IP) - JDBC URL:
?useSSL=true&requireSSL=true&enabledTLSProtocols=TLSv1.2(旧驱动用usessl=true无效) - PHP mysqli:连接时传入
MYSQLI_CLIENT_SSL标志 - PDO DSN:
sslmode=require或完整指定证书路径 - 连接成功后立即执行:
SHOW STATUS LIKE 'Ssl_cipher';—— 返回非空值(如ECDHE-ECDSA-AES256-SHA)才表示当前会话确实在加密
容易被忽略的一点:
require_secure_transport=ON 是全局强制开关,它会拒绝所有未加密的 TCP 连接(包括 root@127.0.0.1),仅靠用户级 REQUIRE SSL 不足以防绕过。











