ThinkPHP启用MySQL双向SSL认证需满足:PHP支持PDO SSL属性、MySQL用户REQUIRE X509、证书由同一CA签发且私钥无密码、Web用户有读取权限、配置中用PDO常量而非快捷键、服务端验证Ssl_client_verify为OK。

ThinkPHP 连接 MySQL 启用 SSL 双向认证的关键条件
ThinkPHP 本身不直接处理 SSL 双向认证(mTLS)的证书校验逻辑,它依赖底层 PDO 或 mysqli 扩展传递连接参数。能否启用双向认证,取决于 PHP 环境是否支持 PDO::MYSQL_ATTR_SSL_CA、PDO::MYSQL_ATTR_SSL_CERT、PDO::MYSQL_ATTR_SSL_KEY 三个属性,且 MySQL 服务端已配置要求客户端提供有效证书。
常见错误现象:PDOException: SQLSTATE[HY000] [2002] SSL connection error 或连接成功但未实际启用加密(抓包可见明文)。根本原因常是证书路径错误、权限不足、或服务端未强制 REQUIRE X509。
- 确认 PHP 编译时启用了 OpenSSL,且
pdo_mysql扩展支持 SSL 属性(PHP 7.4+ 基本满足) - MySQL 用户必须用
CREATE USER ... REQUIRE X509创建,不能只用REQUIRE SSL - 证书文件(
ca.pem、client-cert.pem、client-key.pem)需由同一 CA 签发,且client-key.pem不得有密码(ThinkPHP/PDO 不支持密钥口令) - Web 服务器用户(如 www-data)必须有读取证书文件的权限,路径建议用绝对路径
在 database.php 配置中正确传入 SSL 参数
ThinkPHP 6.x 的数据库配置位于 config/database.php,PDO 连接参数需通过 params 键注入。注意:ThinkPHP 默认忽略未声明的键,sslca、sslcert、sslkey 这类“快捷键”无效,必须用标准 PDO 常量名。
实操示例(仅展示关键片段):
立即学习“PHP免费学习笔记(深入)”;
'debug' => true,
'type' => 'mysql',
'hostname' => 'db.example.com',
'hostport' => 3306,
'username' => 'secure_user',
'password' => 'xxx',
'database' => 'app_db',
'params' => [
\PDO::MYSQL_ATTR_SSL_CA => '/etc/mysql/ssl/ca.pem',
\PDO::MYSQL_ATTR_SSL_CERT => '/etc/mysql/ssl/client-cert.pem',
\PDO::MYSQL_ATTR_SSL_KEY => '/etc/mysql/ssl/client-key.pem',
],
-
\PDO::MYSQL_ATTR_SSL_CA是必需的,即使服务端证书由公共 CA 签发,也建议显式指定以避免证书链验证失败 -
\PDO::MYSQL_ATTR_SSL_CERT和\PDO::MYSQL_ATTR_SSL_KEY必须成对出现,缺一不可——这是双向认证的标志 - 不要在
params中设置\PDO::ATTR_ERRMODE等通用属性,ThinkPHP 已内部管理;重复设置可能干扰异常捕获 - 配置后务必执行
php think optimize:config清除配置缓存,否则修改不生效
验证连接是否真正启用双向 SSL
光看连接不报错不等于双向认证生效。最直接的验证方式是在 MySQL 服务端执行 SHOW STATUS LIKE 'Ssl_%';,并检查 Ssl_client_verify 是否为 OK;同时在 ThinkPHP 中运行原始查询确认上下文:
Db::query('SELECT Ssl_version, Ssl_cipher, Ssl_client_certificate FROM information_schema.SESSION_STATUS WHERE Variable_name IN ("Ssl_version","Ssl_cipher","Ssl_client_certificate")');
- 若
Ssl_client_certificate返回空值或NULL,说明客户端证书未被接受,大概率是证书格式错误(如 PEM 中含多余空行)、私钥有密码、或服务端未设REQUIRE X509 - 若
Ssl_cipher为空,可能是连接被降级到非 SSL 模式,检查 MySQL 错误日志中是否有SSL error: SSL_CTX_use_PrivateKey_file failed - 开发环境可用
openssl s_client -connect db.example.com:3306 -CAfile ca.pem -cert client-cert.pem -key client-key.pem手动测试连通性,绕过 ThinkPHP 排查基础链路
常见兼容性与性能影响
启用双向 SSL 后,每次连接建立会多一次证书交换与验证,连接池复用变得尤为重要。ThinkPHP 默认不开启持久连接(pdo::ATTR_PERSISTENT => false),高并发下易触发连接风暴。
- MySQL 8.0+ 默认禁用旧版 SSL 协议(TLS 1.0/1.1),确保 PHP 的 OpenSSL 版本 ≥ 1.1.1,否则握手失败
- 阿里云 RDS、腾讯云 CDB 等托管服务通常只支持单向 SSL(
REQUIRE SSL),不开放REQUIRE X509,强行配置会导致连接拒绝 - 容器化部署时,证书文件需挂载进 PHP-FPM 容器,且路径与配置中完全一致;使用
getcwd()打印当前工作目录可辅助调试路径问题 - 不要在
params中设置\PDO::MYSQL_ATTR_SSL_CIPHER,多数云厂商不支持自定义加密套件,硬设反而导致协商失败
双向认证真正起效的临界点在于服务端策略和客户端证书的严格匹配,配置项写对只是第一步,证书生命周期管理(比如自动轮换)、私钥保护(避免 chmod 777)、以及错误日志中 SSL 相关字段的持续观测,才是长期稳定的关键。



















