邮件和其他协议

ERROR 2026 SSL connection error:MySQL TLS 连接失败的修法

作者: · 最后核实

报错信息ERROR 2026 (HY000): SSL connection error: error:0A000086:SSL routines::certificate verify failed

ERROR 2026 (HY000): SSL connection error 的意思是:MySQL 客户端没能和服务器完成 TLS 连接。 后面的 OpenSSL 信息说明原因,最常见的是用你提供的 CA 验证不了服务器证书、主机名不匹配,或者客户端和服务器没有共同支持的 TLS 版本。

快速修复

多数情况下,换上和服务器证书匹配的 CA 文件就能连上。先查看服务器出示的证书(需要 OpenSSL 1.1.1 及以上):

openssl s_client -starttls mysql -connect db.example.com:3306 </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -ext subjectAltName -enddate

然后用匹配的 CA 连接:

mysql -h db.example.com -u app -p --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/ssl/certs/db-ca.pem
  • 签发者是 MySQL_Server_..._Auto_Generated_CA_Certificate: 服务器用的是自动生成的证书;VERIFY_CA 用它的 ca.pem,要 VERIFY_IDENTITY 就得换正式证书。
  • 签发者是云厂商的 CA: 从云厂商下载这个 CA。

原因

最常见的是前 3 种:CA 文件不对、自动生成的证书过不了主机名验证、双方没有共同的 TLS 版本。

1. CA 文件不对或没提供

  • 确认: 在 VERIFY_CA 或 VERIFY_IDENTITY 下报 certificate verify failed;上面看到的签发者不是 --ssl-ca 里的 CA。
  • 修复: 使用该签发者的根证书。阿里云 RDS、腾讯云 MySQL、AWS RDS、Azure 等托管数据库,在实例的 SSL 设置页或官方文档里下载 CA 证书。

2. 自动生成的证书遇上 VERIFY_IDENTITY

MySQL Server 首次启动时如果没配置证书,会在数据目录自动生成自签名 CA 和服务器证书。它们的名字是通用的,主机名验证必然失败。

  • 确认: subject 是 MySQL_Server_..._Auto_Generated_Server_Certificate。
  • 修复: 用私有 CA 或公网 CA 签发一张 SAN 包含主机名的服务器证书,再配置:
[mysqld]
ssl_ca   = /etc/mysql/ssl/ca.pem
ssl_cert = /etc/mysql/ssl/server-cert.pem
ssl_key  = /etc/mysql/ssl/server-key.pem
require_secure_transport = ON

MySQL 8.0.16 起可以执行 ALTER INSTANCE RELOAD TLS,不重启就加载新文件。

3. 没有共同的 TLS 版本

  • 确认: 报错里有 unsupported protocol 或 no protocols available;服务器是用旧 TLS 库编译的 5.6/5.7 老版本。
  • 修复: 升级服务器,或在支持的版本上设置 tls_version=TLSv1.2,TLSv1.3。

4. 证书过期

自动生成的证书有效期很长,但你自己安装的证书可能会过期。

  • 修复: 续期、替换文件后执行 ALTER INSTANCE RELOAD TLS(8.0.16+)或重启。

5. 服务器没开 TLS

  • 确认: 报 SSL connection error: SSL is required but the server doesn't support it。
  • 修复: 给服务器配置证书;用 SHOW VARIABLES LIKE '%ssl%'; 检查,客户端里用 \s 查看当前使用的加密套件。

各环境修法

JDBC、PyMySQL、PDO 和 MariaDB 客户端都要做两件事:指定正确的 CA 文件,打开主机名验证。

JDBC(Connector/J 8.x): jdbc:mysql://db.example.com:3306/app?sslMode=VERIFY_IDENTITY&trustCertificateKeyStoreUrl=file:/path/truststore.p12&trustCertificateKeyStorePassword=...,用 keytool -importcert 导入 CA。

Python(PyMySQL / mysqlclient): 传 ssl={"ca": "/path/db-ca.pem"},并开启主机名检查(PyMySQL 用 ssl_verify_identity=True)。

PHP(PDO): PDO::MYSQL_ATTR_SSL_CA => '/path/db-ca.pem',保持 PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT 开启。

MariaDB 客户端: 用 --ssl-ca 配合 --ssl-verify-server-cert 做身份检查。

Docker: 把 CA 挂载进应用容器,数据库证书文件放在卷上,容器重建后不丢失。

宝塔面板安装的 MySQL: 默认没有为客户端连接配置正式证书,远程连接通常落在自动生成的证书上。需要加密的远程访问时,按上文配置证书,并在面板安全设置里只对应用服务器的 IP 放行 3306 端口。

国内云数据库内网连接: 同一 VPC 内用内网地址连接时,确认云厂商的证书覆盖了你使用的连接地址;不覆盖时按云厂商文档选择 VERIFY_CA 或使用证书覆盖的地址。

不要这样做

这些做法要么放弃了服务器身份验证,要么把数据库暴露给公网。

  • 为了消除验证错误退回 --ssl-mode=REQUIRED 或 PREFERRED。 连接加密了,但服务器身份没有验证。
  • 在生产环境的驱动里设置 verifyServerCertificate=false、trustServerCertificate=true 之类的选项。
  • 排查时把 3306 端口暴露到公网。 用安全组限制访问,并保持 TLS 验证开启。

常见问题

MySQL 的 ssl-mode 各个取值是什么意思?

ssl-mode 有 5 个取值,只有 VERIFY_CA 和 VERIFY_IDENTITY 会验证服务器证书。DISABLED:不用 TLS。PREFERRED(默认):服务器支持就用 TLS,不验证。REQUIRED:必须 TLS,但不验证证书。VERIFY_CA:用 --ssl-ca 验证证书。VERIFY_IDENTITY:再检查主机名和证书是否匹配。

MySQL 自动生成的证书,CA 文件在哪里?

在服务器数据目录里,叫 ca.pem,旁边是 server-cert.pem 和 server-key.pem。VERIFY_CA 时把 ca.pem 复制给客户端;要用 VERIFY_IDENTITY,就把这些文件换成 SAN 包含客户端所用主机名的证书。宝塔安装的 MySQL 数据目录一般在 /www/server/data。

Java 报 No appropriate protocol,是同一个问题吗?

是同一类问题,即 Java 里的 TLS 版本不匹配:服务器只提供 TLS 1.0/1.1,而新版 JDK 默认禁用了它们。升级服务器或调整其 TLS 设置,让它支持 TLS 1.2 或 1.3;见 Java SSLHandshakeException。

资料来源

  1. MySQL 8.4 Reference Manual: Using Encrypted Connections
  2. OpenSSL openssl-s_client (-starttls mysql)
  3. OpenSSL X509_STORE_CTX_get_error (verification error codes)