mysql 8.0 在 ubuntu 上启用 ssl 需同时满足编译支持、服务端证书加载、用户 require ssl 和客户端显式启用;关键易错点包括 have_ssl 为 yes、证书属主为 mysql、禁用 apparmor、使用 127.0.0.1 测试而非 localhost。

MySQL 8.0 在 Ubuntu 上默认不强制 SSL,即使证书存在,have_ssl 为 YES 也不代表连接已加密——必须同时满足服务端加载证书、用户级 REQUIRE SSL、客户端显式启用三者,缺一不可。
确认 MySQL 编译时启用了 SSL 支持
这是最容易跳过的前置检查。Ubuntu 官方源的 mysql-server 包默认带 OpenSSL 支持,但如果你用的是精简镜像(如某些 Docker Alpine 镜像)、自编译版本或第三方包,have_ssl 可能是 DISABLED 或 NO,后续所有配置都无效。
- 登录 MySQL 执行:
SHOW VARIABLES LIKE 'have_ssl';,结果必须是YES - 若为
DISABLED,执行SHOW VARIABLES LIKE 'version_ssl_library';查看底层库(OpenSSL / yaSSL);返回空或报错说明未链接加密库 - 修复方式:重装官方包,例如
sudo apt install --reinstall mysql-server(不要只重装 client)
用 mysql_ssl_rsa_setup 生成证书但必须切换用户运行
这个工具只生成文件,不改配置、不重启、不授权,且对运行身份极其敏感——用 root 跑,生成的 server-key.pem 属主是 root,mysqld 读不了,have_ssl 就仍是 DISABLED。
- 先确认数据目录归属:
ls -ld /var/lib/mysql/,输出中属主应为mysql - 切到
mysql用户执行:sudo -u mysql mysql_ssl_rsa_setup --datadir=/var/lib/mysql - 验证生成结果:
sudo -u mysql ls -l /var/lib/mysql/*.pem,确保server-key.pem权限是-rw-------(600)且属主为mysql - 如果报
Permission denied或日志里有SSL_CTX_set_default_verify_paths failed,大概率是 SELinux 或 AppArmor 拦截(Ubuntu 默认用 AppArmor),临时可运行sudo aa-disable /usr/sbin/mysqld排查
在 /etc/mysql/mysql.conf.d/mysqld.cnf 中配绝对路径并重启
配置项写错路径、漏掉 [mysqld] 段、或只 reload 不重启,都会导致证书不加载。SSL 配置不支持热加载。
- 编辑配置文件,在
[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
- 三个路径必须是**绝对路径**;
require_secure_transport = ON是强制所有 TCP 连接走 SSL 的开关,不加它,用户仍可用--ssl-mode=DISABLED绕过 - 改完必须重启:
sudo systemctl restart mysql(不是reload) - 重启后立刻验证:
sudo systemctl status mysql看是否正常启动,再进 MySQL 执行SHOW VARIABLES LIKE 'ssl_%';,确认ssl_ca/ssl_cert/ssl_key均返回非空路径
创建 REQUIRE SSL 用户并用 127.0.0.1 测试连接
localhost 连接默认走 Unix socket,完全绕过 SSL;测试务必用 127.0.0.1 或远程 IP,否则你以为开了 SSL,实际全是明文。
- 新建用户:
CREATE USER 'app'@'%' IDENTIFIED BY 'pwd' REQUIRE SSL; - 已有用户(MySQL ≥ 8.0.22):
ALTER USER 'app'@'%' REQUIRE SSL; - 测试连接:
mysql -u app -p --ssl-mode=VERIFY_CA --ssl-ca=/var/lib/mysql/ca.pem -h 127.0.0.1 - 验证当前连接是否加密:
SELECT Ssl_cipher FROM information_schema.PROCESSLIST WHERE ID=CONNECTION_ID();,返回非空字符串才算成功
真正容易被忽略的是:证书权限、AppArmor 拦截、以及 localhost 连接自动跳过 SSL 这三点。很多“配置完了连不上”的问题,其实压根没走到协议协商那步——mysqld 根本没加载证书,或者连接压根没走 TCP。











