mysql 8.0 默认具备ssl能力但不强制加密;必须同时满足服务端强制(have_ssl=yes且ssl_mode=required)、用户级require ssl限制、客户端显式启用并校验(如--ssl-mode=verify_ca)三者,缺一不可。

MySQL 8.0 默认具备 SSL 能力,但不强制加密;要真正保障传输安全,必须同时满足服务端强制、用户级限制、客户端主动协商三者,缺一不可。
确认 have_ssl 和 ssl_mode 是否就绪
只看 have_ssl 是不够的——它为 YES 仅表示编译支持,不代表已启用加密。必须连查两个变量:
-
SHOW VARIABLES LIKE 'have_ssl';返回YES -
SHOW VARIABLES LIKE 'ssl_mode';必须是REQUIRED或更严格(如VERIFY_CA),不能是默认的PREFERRED
若 ssl_mode 仍是 PREFERRED,说明服务端未强制,所有连接仍可降级为明文。此时改配置或重启都无效,得先配证书路径再开 require_secure_transport = ON。
证书路径与权限必须严格匹配 MySQL 进程身份
证书放错位置、权限不对,MySQL 启动时不会报错,但日志里会静默失败,Ssl_cipher 始终为空。常见踩坑点:
- 证书必须放在
mysql用户可读目录,例如/var/lib/mysql/ca.pem;不能放/home/deploy/ssl/或/root/ -
server-key.pem权限必须是-rw-------(600),否则报SSL error: Unable to get private key - 配置文件中路径必须写绝对路径:
ssl_ca = /var/lib/mysql/ca.pem,不能省略开头的/ - 推荐用内置工具生成:
mysql_ssl_rsa_setup --datadir=/var/lib/mysql --uid=mysql,比手写 OpenSSL 更少出 CN 或 subjectAltName 错误
REQUIRE SSL 不是全局开关,而是逐用户生效
即使服务端开了 require_secure_transport = ON,已有用户仍可能绕过——因为权限控制在用户记录里,不是配置项。
- MySQL 8.0.21 及更早版本:无法对已有用户追加
REQUIRE SSL,只能重建:CREATE USER 'app'@'%' IDENTIFIED BY 'pwd' REQUIRE SSL; - MySQL ≥ 8.0.22:可用
ALTER USER 'app'@'%' REQUIRE SSL; - 验证是否生效:
SELECT user, host, ssl_type FROM mysql.user WHERE user = 'app';,ssl_type应为ANY - 注意:
localhost连接默认走 Unix socket,完全绕过 SSL;测试务必用127.0.0.1或远程 IP
客户端必须显式启用并校验,否则等于没开
服务端配得再严,客户端不配合也白搭。常见误区是以为加了 --ssl-mode=REQUIRED 就安全了——它只加密,不校验证书,防不了中间人。
- 命令行安全连接应为:
mysql -u app -p --ssl-mode=VERIFY_CA --ssl-ca=/path/to/ca.pem - JDBC URL 必须含:
&useSSL=true&requireSSL=true&verifyServerCertificate=true&trustCertificateKeyStoreUrl=file:/path/to/truststore - Python PyMySQL 需传完整 ssl 字典:
ssl={'ca': '/path/to/ca.pem', 'cert': '/path/to/client-cert.pem', 'key': '/path/to/client-key.pem'},只设ssl=True会跳过校验 - PHP 的
mysqli必须显式调用mysqli_ssl_set(),否则全局配置无效
最易被忽略的是:客户端不提供 CA 文件时,VERIFY_CA 会直接拒绝连接,不是警告;而很多文档只教到 REQUIRED 就停了。











