MySQL服务端开启SSL需满足五项必要条件:一是具备PEM格式的ca.pem、server-cert.pem、server-key.pem三证书且私钥权限为600;二是my.cnf中必须显式配置ssl-ca、ssl-cert、ssl-key三项路径;三是确认mysqld实际加载证书(通过SHOW VARIABLES LIKE 'have_ssl'和Ssl_version验证);四是检查错误日志及证书有效期;五是客户端连接时须显式启用SSL模式并正确传递CA证书。

MySQL 服务端开启 SSL 的必要条件
MySQL 要支持 SSL 连接,不是配几个参数就能通的——服务端必须有合法的证书链,且 mysqld 启动时得真正加载它们。否则客户端无论怎么设 ssl-mode=REQUIRED,都会报 SSL connection error: protocol version mismatch 或直接降级为明文。
- 证书文件必须是 PEM 格式:
ca.pem(CA)、server-cert.pem(服务器公钥)、server-key.pem(服务器私钥),三者缺一不可 -
server-key.pem必须权限为600,否则mysqld拒绝读取并静默跳过 SSL 初始化 - 在
my.cnf的[mysqld]段落中,必须显式指定三项路径:ssl-ca、ssl-cert、ssl-key;只写其中两个,SSL 会处于“半启用”状态,SHOW VARIABLES LIKE 'have_ssl'返回DISABLED - 5.7+ 默认编译带 OpenSSL 支持,但若用的是 MySQL 8.0.28+ 的某些小版本(如部分 Alpine 官方镜像),可能默认链接
WolfSSL,导致某些 TLS 1.3 参数不兼容,建议用mysql --version确认 SSL 库类型
验证服务端 SSL 是否真正就绪
别信配置文件写了就完事。最直接的方式是连上去看变量和连接状态:
mysql -u root -p -e "SHOW VARIABLES LIKE 'have_ssl'; SHOW STATUS LIKE 'Ssl_version';"
理想输出是:have_ssl = YES,Ssl_version = TLSv1.3(或 TLSv1.2)。如果 Ssl_version 是空,说明 SSL 没生效;如果 have_ssl = DISABLED,哪怕证书路径全对,也可能是私钥权限不对或 OpenSSL 版本太低。
- 检查错误日志:
tail -n 50 /var/log/mysql/error.log,搜索SSL或Failed to set up SSL,常见提示如SSL error: Unable to get private key from 'server-key.pem' -
openssl x509 -in server-cert.pem -text -noout | grep -E "(Not Before|Not After)"确保证书没过期 - 用
openssl s_client -connect localhost:3306 -servername your-domain.com手动测握手(注意:MySQL 协议本身不走标准 HTTPS 端口,该命令仅测试底层 TLS 握手是否可达)
客户端连接时强制走 SSL 的实际写法
客户端不加约束,默认走明文。即使服务端开了 SSL,只要没明确要求,连接仍可建立——这恰恰是最危险的“假加密”。关键在连接参数,不是 SQL 语句里加什么。
- 命令行工具:
mysql -u user -p --ssl-mode=REQUIRED --ssl-ca=ca.pem;--ssl-mode=VERIFY_IDENTITY更严格,会校验 CN/SAN,适合生产 - Python + PyMySQL:
conn = pymysql.connect(..., ssl={'ca': '/path/to/ca.pem'}, ssl_disabled=False);漏掉ssl_disabled=False会导致自动禁用 SSL - Java JDBC URL 示例:
jdbc:mysql://host:3306/db?useSSL=true&requireSSL=true&verifyServerCertificate=true&trustCertificateKeyStoreUrl=file:/path/to/truststore.jks;注意useSSL=true是旧参数,8.0+ 推荐用sslMode=REQUIRED - Node.js mysql2:
{ ssl: { ca: fs.readFileSync('ca.pem') } },不能只传rejectUnauthorized: true,否则不校验证书链
自签名证书在开发环境的取舍
生产环境必须用 CA 签发的证书(Let’s Encrypt 或企业内网 CA),但开发时用自签名,容易踩两个坑:信任链缺失和主机名不匹配。
- 生成时务必用
subjectAltName(SAN),否则现代客户端(尤其是 Java 和 Go)拒绝接受,错误信息常为CN does not match或unable to verify the first certificate - MySQL 客户端不校验主机名,但很多语言驱动会校验;解决方法是在
openssl.cnf中加入subjectAltName = DNS:localhost,IP:127.0.0.1,再重新签发 - 自签名证书无法规避中间人攻击,仅防网络嗅探;如果开发机连的是公共 WiFi,仍建议用 SSH 隧道替代 SSL
- 别把
server-key.pem提交进 Git——哪怕只是 dev 环境,也该加到.gitignore,这是最容易被忽略的安全疏漏











