MySQL SSL加密连接必须同时满足服务端have_ssl=YES且证书路径可读、用户权限含REQUIRE SSL、客户端显式指定--ssl-mode=REQUIRED三者,缺一不可;否则静默降级为明文。

MySQL SSL 加密连接不是配完证书就自动生效的,必须同时满足服务端加载成功、用户权限绑定 REQUIRE SSL、客户端显式启用 SSL 三者,缺一不可。
确认 have_ssl = YES 且证书路径可读
只看 my.cnf 里写了 ssl_ca 不代表真生效。登录 MySQL 执行 SHOW VARIABLES LIKE '%ssl%';,重点检查三项:
-
have_ssl必须是YES(不是DISABLED或空) -
ssl_ca、ssl_cert、ssl_key值必须是非空的**绝对路径**,例如/var/lib/mysql/ca.pem - 用
sudo -u mysql ls -l /var/lib/mysql/ca.pem /var/lib/mysql/server-key.pem验证文件存在且可读;server-key.pem权限必须是-rw-------(600),属主必须是mysql
常见坑:路径写成 ./ca.pem 或 ~/ca.pem,MySQL 不解析;SELinux 或 AppArmor 拦截读取也会导致静默失败,have_ssl 仍显示 YES 但实际不加密。
用 mysql_ssl_rsa_setup 生成证书最省事
MySQL 8.0+ 自带工具,比手写 OpenSSL 命令更可靠,尤其避免 CN 不匹配、私钥加密等典型错误:
- 先确保数据目录归属正确:
cd /var/lib/mysql && chown mysql:mysql . - 运行:
mysql_ssl_rsa_setup --datadir=/var/lib/mysql --uid=mysql - 生成后默认有
ca.pem、server-cert.pem、server-key.pem—— 这三个就是服务端必需的全部文件 -
client-cert.pem和client-key.pem默认不生成;除非你明确需要双向认证,否则不用管它们
手动生成容易出错:比如用 openssl req -newkey rsa:2048 忘加 -nodes,导致私钥被密码保护,MySQL 启动直接失败。
my.cnf 配置必须写在 [mysqld] 段并重启服务
配置位置和重启方式错了,等于没配:
- 只能写在
[mysqld]段,不能放在[client]或[mysql]—— 那些只影响本地命令行工具 - 路径必须是绝对路径,例如:
ssl-ca = /var/lib/mysql/ca.pem;不要加引号,不要用.或~ - 修改后必须执行
systemctl restart mysqld(不是reload),因为 SSL 参数只在启动时加载 - 重启失败?优先检查
server-key.pem权限是否为 600,再查 MySQL 错误日志:journalctl -u mysqld -n 50 -f
如果启用了 require_secure_transport = ON,所有未走 SSL 的连接会直接拒绝,测试前务必确认客户端已准备就绪。
客户端连接必须显式声明 ssl-mode=REQUIRED
服务端强制了 REQUIRE SSL,但客户端不主动握手,照样连不上或降级为明文:
- 命令行连接示例:
mysql -h 127.0.0.1 -u app -p --ssl-mode=REQUIRED --ssl-ca=/path/to/ca.pem - JDBC 连接串要加:
&useSSL=true&requireSSL=true&trustCertificateKeyStoreUrl=file:/path/to/ca.pem - Python pymysql 示例:
conn = pymysql.connect(..., ssl={'ca': '/path/to/ca.pem'}, ssl_disabled=False) - 注意:
localhost连接默认走 Unix socket,绕过所有 SSL 设置;测试务必用127.0.0.1或真实 IP
最容易被忽略的是:MySQL 用户权限里没设 REQUIRE SSL。执行 SELECT user, host, ssl_type FROM mysql.user; 确认目标用户的 ssl_type 是 ANY 或 X509,而不是 NONE。MySQL 8.0.21 及更早版本不支持对已有用户追加该要求,只能重建用户。


















