mysql ssl加密连接生效必须同时满足:have_ssl=yes、用户权限含require ssl(或x509)、客户端真实完成tls握手;任一缺失均导致静默降级为明文。

MySQL SSL 加密连接不是“配了就生效”,必须同时满足三个硬性条件:服务端证书加载成功(have_ssl = YES)、用户权限明确声明 REQUIRE SSL(或更严格的 REQUIRE X509)、客户端连接时真实完成 TLS 握手。漏掉任意一环,连接都会静默降级为明文。
确认 MySQL 已真正启用 SSL 支持
很多问题卡在这一步:配置写了、证书放了、服务也重启了,但连接仍是明文。根本原因是 MySQL 启动时没加载 SSL 模块。
- 登录 MySQL 执行
SHOW VARIABLES LIKE 'have_ssl';,返回值必须是YES;若为DISABLED或空,说明 SSL 未启用,后续所有操作都无效 - 顺带检查
SHOW VARIABLES LIKE 'tls_version';,确认支持的协议(如TLSv1.2,TLSv1.3),旧客户端连不上时可能需临时放宽,但不建议长期开启 TLSv1.0 -
have_ssl = DISABLED常见于精简版 MariaDB、或手动编译 MySQL 时未加-DWITH_SSL=system;此时重装官方二进制包比自行编译修复更稳妥
生成并放置证书:路径、格式、权限三者缺一不可
MySQL 对证书极其挑剔:只认绝对路径、只读取 PEM 格式、且严格校验文件权限。相对路径、~/、权限 >600 的私钥都会导致启动失败或连接拒绝。
- 优先用内置工具生成(MySQL 8.0+):
mysql_ssl_rsa_setup --datadir=/var/lib/mysql --uid=mysql,它自动处理 CN 和 subjectAltName,避免手动生成时常见的X509_V_ERR_IP_ADDRESS_MISMATCH错误 - 证书必须放在 MySQL 进程有读权限的目录,例如
/var/lib/mysql/ca.pem,不能放/root/或/home/deploy/下 - 检查权限:
sudo -u mysql ls -l /var/lib/mysql/ca.pem /var/lib/mysql/server-key.pem,其中server-key.pem必须是-rw-------(即 600);MySQL 启动时会拒绝读取权限过宽的私钥 - 证书链必须由同一 CA 签发;若服务通过
127.0.0.1和db.example.com访问,server-cert.pem的subjectAltName必须显式包含这两项
服务端强制加密:require_secure_transport = ON 是关键开关
require_secure_transport = ON 不是可选优化项,而是生产环境的底线配置。它拒绝所有非 SSL 连接,比只设 ssl=ON 或仅依赖用户权限更可靠。
- 在
my.cnf的[mysqld]段添加:[mysqld] ssl_ca = /var/lib/mysql/ca.pem ssl_cert = /var/lib/mysql/server-cert.pem ssl_key = /var/lib/mysql/server-key.pem require_secure_transport = ON
- 改完必须
systemctl restart mysql(不是reload),SSL 配置不支持热加载 - 注意:该配置会全局拒绝非 SSL 连接,包括本地
mysql -u root -p;如需保留本地免证书登录,可额外创建localhost用户并跳过REQUIRE,但不推荐
验证连接是否真加密:别信 status,要看当前会话
SHOW VARIABLES LIKE '%ssl%' 只反映服务端配置,不代表你的连接已加密。真正有效的是当前会话的加密状态。
- 连接后立即执行:
SELECT Ssl_cipher FROM performance_schema.session_status WHERE variable_name = 'Ssl_cipher';,返回非空字符串(如ECDHE-RSA-AES256-GCM-SHA384)才表示本次连接已走 TLS - 用客户端连接时务必传全参数:
mysql -u secure_user -p --ssl-ca=ca.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem;少一个参数,MySQL 就可能回退到非加密连接 - 若用 JDBC 或 Python
mysql-connector,必须显式设置ssl_disabled=False并传入证书路径;某些驱动默认关闭 SSL,即使服务端强制也不起作用 - 最容易被忽略的一点:客户端证书权限也必须是 600,否则部分驱动(如 mysql-connector-python)会静默忽略证书,导致连接失败却不报错











