mysql 5.7 支持双向 ssl,但默认关闭;需手动生成无密码私钥、含 subjectaltname 和 clientauth 的证书链,配置 require_secure_transport=on、ssl_ca/cert/key 四项参数,创建用户时用 create user ... require x509,并通过 mysql 命令显式传入 --ssl-mode=required 等参数才能生效。

MySQL 5.7 支持双向 SSL,但默认完全关闭;必须手动生成兼容证书、修改 my.cnf、启用强制加密,并在创建用户时用 REQUIRE X509 绑定证书校验逻辑——漏掉任一环节都会导致连接失败或降级为单向验证。
生成 MySQL 5.7 兼容的双向证书链
MySQL 5.7 对证书格式敏感:私钥不能加密(即不能有 passphrase),证书必须含正确 extendedKeyUsage,且服务端证书需带 subjectAltName(否则客户端连接报 ERROR 2026 (HY000): SSL connection error: Certificate verification failed)。
- CA 根证书必须用
openssl req -x509生成,不能跳过-nodes;生成后检查:openssl x509 -in ca.pem -text -noout | grep "CA:"应显示CA:TRUE - 服务端证书请求必须包含
subjectAltName,推荐用配置文件方式生成(避免命令行遗漏);最小可用配置:[req] distinguished_name = req_distinguished_name x509_extensions = v3_req [req_distinguished_name] [v3_req] subjectAltName = @alt_names [alt_names] DNS.1 = localhost IP.1 = 127.0.0.1
- 客户端证书必须明确声明
clientAuth:执行openssl x509 -req -in client-req.pem -CA ca.pem -CAkey ca-key.pem -set_serial 02 -out client-cert.pem -extfile - 所有 PEM 文件(
ca.pem、server-cert.pem、client-cert.pem、server-key.pem、client-key.pem)属主必须是mysql用户,否则 mysqld 启动时静默失败,日志只显示Failed to set up SSL
my.cnf 中必须设置的 4 个 SSL 配置项
require_secure_transport = ON 是双向验证的“总开关”——它让 MySQL 拒绝任何非 SSL 连接;而 ssl_mode = REQUIRED 只影响客户端行为,对服务端无约束力。两者不可互换。
-
require_secure_transport = ON:强制所有连接走 TLS,否则直接拒绝(错误码ERROR 3159 (HY000)) -
ssl_ca = /etc/mysql/ssl/ca.pem:必须指向包含客户端 CA 的文件;若客户端证书由中间 CA 签发,此处需合并根 CA + 中间 CA -
ssl_cert = /etc/mysql/ssl/server-cert.pem和ssl_key = /etc/mysql/ssl/server-key.pem:路径必须绝对,且私钥不能加密 - 可选但强烈建议:
ssl_crl = /etc/mysql/ssl/crl.pem;不配的话,后续吊销客户端证书将完全无效
CREATE USER 必须带 REQUIRE X509,GRANT 不生效
GRANT ... REQUIRE X509 是无效语法;MySQL 5.7 只认 CREATE USER 或 ALTER USER 语句中的 REQUIRE 子句。权限和证书验证是两套机制,混用会导致“看起来配了,实则没校验”。
- 正确写法:
CREATE USER 'app'@'%' REQUIRE X509;或更严格地:CREATE USER 'app'@'%' REQUIRE SUBJECT '/CN=app-client/O=myorg'; -
SUBJECT值必须与openssl x509 -in client-cert.pem -subject -noout输出**逐字匹配**,包括空格、大小写、字段顺序;常见坑:OU=devvsOU=Dev - 对已有用户执行
ALTER USER 'app'@'%' REQUIRE X509会覆盖之前所有REQUIRE条件,不是叠加 - 验证是否生效:
SELECT user, host, ssl_type, ssl_cipher FROM mysql.user WHERE user = 'app';,ssl_type应为X509
mysql 命令行连接必须显式传参,不读取系统配置
MySQL 客户端不会自动加载 /etc/my.cnf 或环境变量里的 SSL 设置;漏掉任意一个参数,错误信息往往误导人(比如报 Access denied for user,实际是证书未提供或校验失败)。
- 最小可行命令:
mysql --ssl-mode=REQUIRED --ssl-ca=/etc/mysql/ssl/ca.pem --ssl-cert=/etc/mysql/ssl/client-cert.pem --ssl-key=/etc/mysql/ssl/client-key.pem -u app -p -
--ssl-mode=REQUIRED不可省略或降级为PREFERRED;设成VERIFY_IDENTITY则还会校验服务端证书 CN 是否匹配连接地址 -
--ssl-cert和--ssl-key必须成对出现;私钥若有密码,mysql 客户端不支持交互输入,连接必然失败 - 调试技巧:加
--debug-info查看握手细节,或用openssl s_client -connect localhost:3306 -cert client-cert.pem -key client-key.pem -CAfile ca.pem单独测试 TLS 层
最易被忽略的是证书的 extendedKeyUsage 字段和 subjectAltName ——它们不体现在常见 OpenSSL 一键脚本里,但 MySQL 5.7 在握手阶段会严格检查;一旦缺失,错误日志里既不提示具体原因,也不输出证书内容,只能靠 openssl x509 -text 逐个比对。











