mysql ssl协议版本不匹配需统一为tlsv1.2/tlsv1.3;require ssl仅加密,require x509强制双向认证;ssl_ca等路径必须用绝对路径且权限严格;docker中应挂载宿主机证书并设只读。
mysql 连接报错 ssl connection error: protocol version mismatch 怎么办
这通常不是证书本身有问题,而是客户端和服务端 ssl 协议版本协商失败。mysql 5.7+ 默认禁用旧版 tls(如 tlsv1.0),但某些老客户端(比如旧版 mysql connector/python 或 shell 中的 mysql 命令)仍尝试用它握手。
实操建议:
- 先确认服务端支持的协议:登录 MySQL 后执行
SHOW VARIABLES LIKE 'tls_version';,常见值是TLSv1.2,TLSv1.3 - 客户端连接时显式指定协议:用
mysql --ssl-mode=REQUIRED --tls-version=TLSv1.2 -h host -u user -p - 若用 Python 的
pymysql,必须传ssl={'ssl': {}},不能只写ssl=True;mysql-connector-python则需设ssl_disabled=False且配合tls_versions=['TLSv1.2'] - OpenSSL 版本太低(如 1.0.2)也会触发此错,升级到 1.1.1+ 更稳妥
REQUIRE SSL 和 REQUIRE X509 在 GRANT 语句里有啥区别
REQUIRE SSL 只强制走加密通道,不校验证书;REQUIRE X509 则要求客户端提供有效证书,并由服务端 CA 验证签名——这是真正双向认证的关键一步。
实操建议:
- 普通业务连接够用的是
REQUIRE SSL,例如:GRANT SELECT ON db.* TO 'app'@'%' REQUIRE SSL; - 需要绑定特定客户端身份时,才用
REQUIRE X509,此时用户必须用--ssl-cert和--ssl-key连接,服务端还得配好ssl_ca -
REQUIRE SUBJECT '/CN=client1'或REQUIRE ISSUER是更细粒度控制,但一旦证书重签或 CN 改变,权限立刻失效,运维成本高 - 注意:所有
REQUIRE类型都只对新连接生效,已存在的连接不受影响
MySQL 的 ssl_ca、ssl_cert、ssl_key 路径填绝对路径还是相对路径
必须填**绝对路径**。MySQL 服务启动时以 mysqld 进程用户(通常是 mysql)身份读取这些文件,相对路径会相对于 datadir 或启动目录,极难预测,几乎必然失败。
实操建议:
- 检查路径权限:
sudo -u mysql ls -l /etc/mysql/ssl/server-ca.pem,确保mysql用户可读 - 配置文件中写死绝对路径,例如:
ssl_ca = /etc/mysql/ssl/ca.pem,不要用~/或./ - 证书和私钥不能放同一目录且权限宽松,否则 MySQL 启动直接拒绝加载:
ssl_key文件权限必须 ≤600,否则报错Failed to set mode of ssl_key file - 修改配置后,用
mysql --help --verbose 2>/dev/null | grep ssl确认参数是否被正确解析
用 Docker 运行 MySQL 时证书路径怎么映射才不踩坑
Docker 容器内路径和服务宿主机路径是隔离的,把证书放在容器外再挂载进来最安全。硬编码进镜像或用 COPY 构建时嵌入,会导致证书更新必须重打镜像。
实操建议:
- 宿主机上统一放证书到
/opt/mysql-ssl/,然后用-v /opt/mysql-ssl:/etc/mysql/ssl:ro挂载 - MySQL 配置里写
ssl_ca = /etc/mysql/ssl/ca.pem,和挂载目标路径一致 - 别用
docker run --mount type=bind时漏掉:ro,私钥被容器进程意外写入会破坏安全性 - 如果用 docker-compose,注意
environment:下不能覆盖ssl_*配置项,它们只从my.cnf读取,不是环境变量控制的
证书链顺序、私钥是否加密、CA 是否自签名——这些细节在报错信息里往往藏得不明显,但每次连不上,大概率就卡在这三处之一。










