doctrine mysql连接必须显式启用ssl参数,如?ssl_mode=required&ssl_ca=/path/to/ca.pem,否则默认走明文;服务端需先启用ssl,客户端证书路径须为绝对路径且php进程可读,验证应查show status like 'ssl_cipher'非空。

Doctrine URL 中必须显式启用 SSL 参数
默认的 DATABASE_URL 不启用 MySQL SSL,哪怕数据库服务端已配置好证书,连接仍走明文。必须在 URL 末尾追加 ?sslmode=require(PostgreSQL)或 &ssl_mode=REQUIRED(MySQL)。Symfony 6.4 使用 Doctrine DBAL 3.x/4.x,其 MySQL 驱动(pdo_mysql)只认 ssl_mode、ssl_ca、ssl_cert、ssl_key 这类原生 PDO 参数,不识别 sslmode。
正确写法示例(MySQL):
DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?ssl_mode=REQUIRED&ssl_ca=/path/to/ca-cert.pem&ssl_cert=/path/to/client-cert.pem&ssl_key=/path/to/client-key.pem"
-
ssl_mode=REQUIRED是最低安全要求;若服务端强制验证客户端证书,需改用VERIFY_IDENTITY - 路径必须是绝对路径,相对路径(如
./certs/ca.pem)在 CLI 环境下常因工作目录不同而失败 - 所有证书文件需对 PHP 进程可读(注意 SELinux 或 Docker 容器内权限)
doctrine.yaml 中不能覆盖 URL 里的 SSL 设置
config/packages/doctrine.yaml 里的 doctrine.dbal.url 若为字符串,会完全替代 .env 中的 DATABASE_URL;若使用 %env(resolve:DATABASE_URL)% 引用,则 SSL 参数必须全部塞进环境变量里——doctrine.yaml 本身不提供独立配置 SSL 的字段。
错误做法:
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
doctrine:
dbal:
url: '%env(resolve:DATABASE_URL)%'
# 下面这些 ssl_* 配置会被忽略
options:
ssl_ca: '/path/to/ca.pem'
- DBAL 不解析
options下的 SSL 键,只认 URL 查询参数 - 想复用环境变量又保持清晰,可把证书路径也设为环境变量:
SSL_CA_PATH=/path/to/ca.pem,再拼接 URL - 修改后务必清缓存:
php bin/console cache:clear --env=prod(生产环境)
连接失败时最常被忽略的三个点
报错如 SQLSTATE[HY000] [2002] Connection refused 或 SSL connection error: protocol version mismatch,大概率不是配置漏写,而是:
- MySQL 服务端未开启 SSL:执行
SHOW VARIABLES LIKE 'have_ssl';,返回DISABLED就得先配好服务端证书并重启 mysqld - 客户端证书与 CA 不匹配:用
openssl verify -CAfile ca-cert.pem client-cert.pem手动验签 - PHP 的 OpenSSL 扩展未启用或版本过低:运行
php -m | grep openssl,且确认openssl_version()≥ 1.1.1(旧版不支持 TLS 1.3,某些云数据库强制要求)
测试 SSL 是否真正生效
光看 doctrine:database:create 成功没用——它可能绕过 SSL。真验证得查连接握手细节:
在控制器或命令中执行:
$conn = $this->getDoctrine()->getConnection();
$sslStatus = $conn->fetchOne('SHOW STATUS LIKE "Ssl_cipher"');
// 返回非空字符串(如 'TLS_AES_256_GCM_SHA384')才表示 SSL 已激活
- 别依赖
SHOW VARIABLES LIKE 'ssl_%',那是服务端配置,不是当前连接状态 - Docker 环境下,宿主机证书路径映射进容器后,路径在容器内必须一致
- Cloud SQL / RDS 等托管服务通常只要求
ssl_mode=REQUIRED+ssl_ca,无需客户端证书










