MySQL安装后默认不会启用加密传输,这一安全漏洞往往被忽视。即便您费心配置了SSL证书,连接仍可能以明文方式传输——关键在于必须手动将服务端强制策略、用户权限设置与客户端连接行为三者联动配置,任何一环缺失都无法实现真正的加密连接。

许多开发者以为生成证书后就能高枕无忧,但默认情况下MySQL依然采用明文传输——必须手动完成服务端强制策略、用户权限和客户端行为的三方联动配置,缺一不可。
确认ha ve_ssl状态是否为YES,而非DISABLED
不少问题都卡在第一步:配置修改了、证书也放置了、服务也重启了,但执行SHOW VARIABLES LIKE 'ha ve_ssl'返回的结果却是DISABLED或者干脆为空值。这并非配置未生效,而是mysqld启动时根本没有加载OpenSSL模块。
- 首先执行
SHOW VARIABLES LIKE 'ssl_ca'、ssl_cert、ssl_key,这三个系统变量必须都返回非空的绝对路径,且对应的证书文件真实存在于磁盘上。 ha ve_ssl = DISABLED在MariaDB精简版、Alpine镜像,或者编译时未添加-DWITH_SSL=system参数的情况下经常出现——直接重装官方二进制包比折腾编译要靠谱得多。- 顺手检查一下
SHOW VARIABLES LIKE 'tls_version',确认数据库支持TLSv1.2或TLSv1.3协议。旧客户端无法连接时可临时放宽版本要求,但切勿长期开启TLSv1.0。
证书路径、格式与权限三者必须同时满足合规要求
MySQL对证书的校验相当严格:只接受绝对路径、仅支持PEM格式、私钥权限必须为600。使用相对路径、~/符号,或者私钥权限大于600,都会导致启动失败或连接被拒绝。
- 优先使用内置工具生成(MySQL 5.7.6及以上版本):
mysql_ssl_rsa_setup --datadir=/var/lib/mysql --uid=mysql,该工具能自动处理好subjectAltName扩展,避免出现X509_V_ERR_IP_ADDRESS_MISMATCH这类烦人的证书校验错误。 - 证书文件必须放置在MySQL进程拥有读取权限的目录,例如
/var/lib/mysql/ca.pem,切勿放在/root/或/home/deploy/等受限目录下。 - 立即修正文件权限:
chown mysql:mysql /var/lib/mysql/*.pem && chmod 600 /var/lib/mysql/server-key.pem。MySQL会拒绝读取组账户或其他用户可读的私钥文件。 - 私钥不能带有密码保护——如果存在密码,使用
openssl rsa -in server-key.pem -out server-key.pem命令去除密码。
require_secure_transport = ON 是生产环境的底线配置
require_secure_transport = ON并非可选的性能优化项,而是强制所有TCP连接都必须走SSL加密的硬性开关。仅设置ssl=ON或者只依赖用户权限控制,都可能被绕过而退回明文传输。
- 编辑
/etc/my.cnf或/etc/mysql/mysql.conf.d/mysqld.cnf配置文件,仅在[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
- 路径必须使用绝对路径,不能使用
~/或相对路径;也不要写在[client]段中——那是客户端配置,对服务端不生效。 - 修改完成后必须执行
systemctl restart mysqld(而不是reload),SSL配置不支持热加载。 - 重启后立即检查MySQL错误日志:
tail -n 50 /var/log/mysqld.log | grep -i ssl。如果出现Failed to set up SSL错误,说明证书文件或权限存在问题。
验证当前连接是否真正走SSL,不要只看status,要查Ssl_cipher
SHOW VARIABLES LIKE '%ssl%'只能告诉你“配置了哪些参数”,而STATUS或s才能反映当前连接的实际加密状态。最直接的方法是查询Ssl_cipher变量。
- 连接MySQL后执行:
SELECT Ssl_cipher FROM information_schema.PROCESSLIST WHERE ID=CONNECTION_ID(); - 返回结果为空字符串或
NULL→ 当前连接未使用SSL加密。 - 返回类似
ECDHE-ECDSA-AES256-SHA或TLS_AES_256_GCM_SHA384→ 连接已加密。 - 客户端连接时必须显式启用SSL:
mysql -u app -p --ssl-mode=REQUIRED;而mysql -u root -p默认不启用SSL。 - JDBC连接需添加
&useSSL=true&requireSSL=true参数;PyMySQL需传入ssl={'ca': '/path/to/ca.pem'},仅设置ssl=True会跳过证书校验,失去防中间人攻击的保护意义。
最容易被忽略的一点是:开启require_secure_transport=ON之后,所有未显式启用SSL的客户端连接会被直接拒绝,但错误提示仍然显示为Access denied,而不是SSL相关的报错信息——这意味着你需要从客户端日志或MySQL错误日志中查找SSL connection error才能定位真实原因。
