REQUIRE SSL 不生效主因是服务端未启用 SSL,需先执行 SHOW VARIABLES LIKE 'have_ssl' 确认返回 YES,再检查 ssl_ca、ssl_cert、ssl_key 为非空绝对路径且权限正确,否则所有客户端配置无效。

REQUIRE SSL 不生效,90% 是服务端压根没启用 SSL,而不是用户语法写错了。 它不会报错,也不会拒绝连接——它只是安静地退化成明文连接。必须从服务端证书加载状态开始排查,否则所有客户端配置都是徒劳。
检查 MySQL 实例是否真正启用了 SSL
这是第一步,也是最容易被跳过的致命环节。执行 SHOW VARIABLES LIKE 'have_ssl';,返回值必须是 YES;若为 DISABLED 或 NO,说明 OpenSSL 库未加载或配置缺失,后续所有操作都无效。
-
ssl_ca、ssl_cert、ssl_key三个变量必须是非空的**绝对路径**,且 MySQL 进程(通常是mysql用户)有读权限;相对路径、符号链接、放错目录(如丢进/etc/mysql/conf.d/却没include)都会导致加载失败 - Docker 或云数据库(如 RDS)默认可能只开启 TLS 1.2+ 协商能力,但未启用完整 SSL 握手支持,
REQUIRE SSL会静默失效 - Linux 下 SELinux 或 AppArmor 可能拦截访问,临时执行
setenforce 0测试可快速验证是否为此类权限问题
创建或修改用户时 REQUIRE SSL 的实际效果
REQUIRE SSL 只约束 TCP 连接,对 localhost(Unix socket)完全无效——它直接绕过所有网络层校验。测试务必用 127.0.0.1 或远程 IP,否则永远看不到加密效果。
- 新建用户:使用
CREATE USER 'app'@'%' IDENTIFIED BY 'pwd' REQUIRE SSL; - 修改已有用户(MySQL ≥ 8.0.22):用
ALTER USER 'app'@'%' REQUIRE SSL;,但必须跟FLUSH PRIVILEGES;才能让新策略对后续连接生效;已有活跃连接不受影响 - 注意认证插件兼容性:
caching_sha2_password是 MySQL 8.0 默认插件,与 SSL 正交,但旧版 PHP mysqli、某些 JDBC 驱动不支持该插件 + SSL 组合,会报Authentication plugin 'caching_sha2_password' cannot be loaded;可显式指定插件:CREATE USER 'app'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd' REQUIRE SSL;
客户端必须主动发起 SSL 握手,不能依赖服务端强制
哪怕服务端设了 REQUIRE SSL,JDBC、pymysql、mysql CLI 等客户端默认仍走明文——它们根本不会发 Client Hello。结果不是“证书错误”,而是直接 Access denied。
- 命令行连接:必须加
--ssl-mode=REQUIRED,仅--ssl或--ssl-mode=PREFERRED会自动降级,无法验证是否真加密 - JDBC URL 示例:
jdbc:mysql://host:3306/db?sslMode=REQUIRED&enabledTLSProtocols=TLSv1.2;useSSL=true已废弃,不生效 - Java 客户端若用自签名证书,避免
verifyServerCertificate=true(等价于--ssl-mode=VERIFY_IDENTITY),因为自签证书 CN 通常为localhost,与连接地址不匹配,直接拒绝 - 验证是否真加密:登录后执行
STATUS;,看输出中是否有SSL: Cipher in use is;或查SELECT VARIABLE_VALUE FROM performance_schema.status_by_thread WHERE VARIABLE_NAME = 'Ssl_cipher' AND THREAD_ID = CONNECTION_ID();,非空即表示当前连接已加密
require_secure_transport=ON 是全局强制开关,但不是万能解
它只阻止非 SSL 的 TCP 连接,但不影响 Unix socket、本地文件导入、复制通道等其他入口。要真正堵死明文通路,需组合策略:
- 必须设
require_secure_transport = ON(在my.cnf的[mysqld]段),并重启 mysqld;仅 reload 不生效 - 所有用户都应带
REQUIRE SSL,否则该参数对这些用户无效 - 应用连接禁用
localhost,统一改用127.0.0.1强制走 TCP - 服务端
tls_version需与客户端匹配;MySQL 8.0.28+ 默认为TLSv1.2,TLSv1.3,老客户端报protocol version mismatch时,可临时调宽:SET GLOBAL tls_version = 'TLSv1,TLSv1.1,TLSv1.2';(不推荐长期用于生产)
最常被忽略的是:证书私钥必须无密码、PEM 格式、与证书匹配,且 ssl_cipher 变量非空才代表握手链跑通。抓包验证(tcpdump -i lo port 3306 + Wireshark)仍是最终裁决手段——如果能看到明文 SELECT,那就肯定没加密。


















