答案:mysql真正启用ssl需满足have_ssl= yes且ssl_ca、ssl_cert、ssl_key三项变量均有非空绝对路径值;否则客户端即使配置require ssl也无法连接。

确认 MySQL 是否真正启用了 SSL 支持
没启用 SSL,后面所有配置都无效。直接登录 MySQL 执行 SHOW VARIABLES LIKE 'have_ssl';,结果必须是 YES。如果返回 DISABLED 或空值,说明 OpenSSL 模块根本没加载——此时别急着改用户权限或客户端参数,先检查:
• ssl_ca、ssl_cert、ssl_key 三个变量是否非空且为绝对路径(如 /var/lib/mysql/ca.pem)
• 证书文件属主是否为 mysql 用户,权限是否为 600(尤其是 server-key.pem)
• SELinux 或 AppArmor 是否拦截了 mysqld 对证书路径的读取(临时执行 setenforce 0 测试可快速验证)
配置 require_secure_transport=ON 强制全局加密
仅给用户加 REQUIRE SSL 不够,它只校验已建立的连接是否走 TLS;而 require_secure_transport=ON 是服务端协议层开关,会直接拒绝所有未加密的 TCP 连接(包括 root@127.0.0.1),这才是真正的“强制”。
• 运行时启用(推荐):SET PERSIST require_secure_transport = ON;
• 配置文件启用:在 [mysqld] 段添加 require_secure_transport = ON,然后 systemctl restart mysqld
• 验证是否生效:SELECT @@GLOBAL.require_secure_transport; 返回 1 才算成功
注意:Unix socket 连接(如 localhost 本地连接)默认不受影响,除非显式禁用
客户端必须显式声明 SSL 模式才能握手成功
服务端开了强制加密,客户端不主动发起 TLS 握手,连接会被直接终止,错误提示常是 Access denied for user,但这不是认证失败,而是协议被拦在门外。
• 命令行:mysql -u appuser -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 就会失败
用户级 REQUIRE SSL 与全局强制的区别和配合
REQUIRE SSL 是账户级约束,只对该用户生效,但前提是服务端 SSL 已启用;require_secure_transport=ON 是全局策略,对所有 TCP 连接生效。两者不是替代关系,而是叠加保障:
• 创建用户时加 REQUIRE SSL:CREATE USER 'appuser'@'10.0.2.%' IDENTIFIED BY 'p4ssw0rd' REQUIRE SSL;
• 已有用户追加:ALTER USER 'appuser'@'10.0.2.%' REQUIRE SSL;
• MySQL 8.0.21 及更早版本不支持对已有用户追加 REQUIRE SSL,只能重建用户
关键点:即使开了 require_secure_transport=ON,仍建议关键账号也加 REQUIRE SSL,防止未来配置变更导致降级风险











