ThinkPHP数据库SSL加密必须通过config/database.php中connections.mysql.params关联数组配置,键名严格使用PDO常量(如\PDO::MYSQL_ATTR_SSL_CA),值为Web进程可读的绝对路径证书文件,缺一不可。

ThinkPHP 数据库 SSL 加密不是“开关一开就生效”,而是必须通过 params 数组显式传入 PDO 原生 SSL 属性,路径、常量、权限三者缺一不可,否则连接会静默降级或直接报错。
ThinkPHP 6 的 database.php 中 params 是唯一有效入口
框架不会从 DSN(如 mysql://user:pass@host/db?ssl_mode=REQUIRED)解析 SSL 参数,params 数组是 PDO 连接构造前唯一能透传 SSL 配置的地方。写错位置等于没配。
-
params必须是关联数组,键名严格使用 PDO 常量:PDO::MYSQL_ATTR_SSL_CA、PDO::MYSQL_ATTR_SSL_CERT、PDO::MYSQL_ATTR_SSL_KEY、PDO::MYSQL_ATTR_SSL_MODE - 值不能是字符串
'PDO::MYSQL_ATTR_SSL_CA',也不能小写,否则被忽略 - 证书路径必须是服务器本地绝对路径,例如
/etc/mysql/ssl/ca.pem,./ca.pem或certs/ca.pem全部失败 - PHP 进程用户(如 www-data 或 nginx)必须有读取这些文件的权限,SELinux 启用时还需检查上下文
SSL_MODE 设为 REQUIRED 还是 VERIFY_IDENTITY?
选哪个取决于你的 MySQL 服务端配置和部署环境。盲目设 PDO::MYSQL_ATTR_SSL_MODE_VERIFY_IDENTITY 是线上最常见的连接失败原因。
-
PDO::MYSQL_ATTR_SSL_MODE_REQUIRED(值为1):只加密,不校验服务端证书域名和签名。适用于内网、自签名 CA、测试环境 -
PDO::MYSQL_ATTR_SSL_MODE_VERIFY_CA(值为2):校验证书链是否由指定 CA 签发,但不校验域名。需确保PDO::MYSQL_ATTR_SSL_CA指向正确的根证书 -
PDO::MYSQL_ATTR_SSL_MODE_VERIFY_IDENTITY(值为3):最严格,既校验证书链又校验Common Name或Subject Alternative Name是否匹配 MySQL 服务端域名。公网云数据库(如阿里云 RDS、腾讯云 CDB)通常要求这个,但自建 MySQL 很少满足
ThinkPHP 5 不支持服务端证书校验,别白费力气
TP5 的数据库参数白名单里压根没包含 PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT,你就算把 CA 路径和 VERIFY_IDENTITY 全写对,PDO 构造时也收不到这个参数——连接能通,但证书校验根本没跑。
立即学习“PHP免费学习笔记(深入)”;
- 现象:删掉 CA 文件几行,连接照样成功;
SHOW STATUS LIKE 'Ssl_cipher'有值,但抓包看不到 CertificateVerify 握手消息 - 结论:TP5 只能做传输加密(防嗅探),不能防中间人(MITM)。生产环境强依赖证书校验的场景,请升级到 TP6.1+
- 最小可行配置(TP5):
PDO::MYSQL_ATTR_SSL_CA+PDO::MYSQL_ATTR_SSL_MODE_REQUIRED,其余参数无效
常见错误和快速定位方法
报错 SQLSTATE[HY000] [2002] SSL connection error 或连接成功但明文传输,90% 不是 ThinkPHP 配错了,而是底层条件没满足。
- 先登录 MySQL 执行
SHOW VARIABLES LIKE '%ssl%';,确认have_ssl = YES,且ssl_ca、ssl_cert、ssl_key非空 - 查用户是否强制 SSL:
SELECT user, host, ssl_type FROM mysql.user WHERE user = 'your_user';,若ssl_type是ANY或X509,客户端必须提供完整证书链 - 用
tcpdump -i any port 3306 -w mysql.pcap抓包,Wireshark 打开后看 TLS 握手阶段有没有Certificate和CertificateVerify消息 - ThinkPHP 日志里出现
PDO::__construct(): SSL operation failed,优先检查证书路径是否存在、PHP 进程能否读、私钥是否带密码(TP 不支持解密带密码的.key)
真正难的不是写那几行配置,而是证书路径权限、MySQL 服务端策略、客户端驱动行为三者对齐。漏掉任意一环,SSL 就只是个摆设。



















