PHP命令行运行PDO报MySQL访问拒绝错误 但Apache环境下正常
CLI 环境下 PDO 连接 MySQL 报 1045 错误的排查方案
适用场景:同套代码在Apache Web环境下连接数据库正常,MySQL命令行工具可正常连接,所有数据库用户在CLI执行时统一抛出SQLSTATE[HY000] [1045] Access denied错误,已排除凭据错误、服务端权限配置问题。
最高发原因:PHP CLI 与 Apache 的 socket 配置不匹配
- 当PDO的DSN配置host为
localhost时,连接不会走TCP协议,而是直接读取PHP配置里的pdo_mysql.default_socket参数值,通过Unix本地socket和MySQL通信。 - 快速核对步骤:
- CLI下执行
php -i | grep pdo_mysql.default_socket,拿到CLI实际生效的socket路径 - 执行
mysql_config --socket拿到MySQL服务实际监听的socket路径 - 对比两个路径是否完全一致。
- CLI下执行
Ubuntu系统更新OpenSSL相关依赖时,往往会顺带升级PHP的deb安装包,容易出现CLI侧加载的php.ini指向其他版本配置文件的问题,导致socket路径和MySQL实际监听路径不匹配。此时PDO尝试连接错误socket时,MySQL服务会直接返回1045权限拒绝,而非socket文件不存在的报错,和该场景的现象完全吻合。
- 验证方法:临时修改DSN为socket直连模式,格式为
mysql:unix_socket=/var/run/mysqld/mysqld.sock;dbname=dbname;charset=utf8,如果连接成功,即可确认是socket配置不匹配问题。 - 解决方式:将CLI侧php.ini里的
pdo_mysql.default_socket值修改为MySQL实际的socket路径,无需重启MySQL,下次执行CLI脚本即可生效。
次高发原因:环境变量干扰
- CRON执行环境的变量加载逻辑和交互式Shell、Apache完全独立,容易残留历史配置的环境变量:
- 如果环境中存在
MYSQL_PWD变量,PDO依赖的libmysqlclient库会优先读取该值作为连接密码,直接覆盖代码里传入的密码参数,导致认证失败。 - 同时检查是否存在
MYSQL_HOST类变量,会自动覆盖DSN里配置的host参数。
- 如果环境中存在
- 验证方法:执行CLI命令前清空全量环境变量,运行
env -i PATH=$PATH php dispatchCLI.php task=first,如果连接恢复正常,即可确认是环境变量干扰。 - 解决方式:在CRON任务脚本开头清空相关的MySQL环境变量,或修正过期的变量值。
OpenSSL升级关联的兼容问题
- 系统更新OpenSSL时会触发依赖链更新,容易导致PHP pdo_mysql扩展动态链接的libmysqlclient版本发生偏移,出现密码认证握手不兼容的问题,表现为固定的1045错误,无明确握手失败提示。
- 验证方法:临时在PDO连接选项里关闭SSL证书校验,设置
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,同时临时关闭服务端的强制SSL连接配置,测试是否可正常连接。 - 解决方式:通过
apt reinstall php-mysql命令重装对应版本的扩展包,让扩展链接的libmysqlclient版本和当前系统环境对齐。
无需浪费时间排查的方向
- 不用反复核对数据库用户的权限配置:同套代码在Apache环境下已经可以正常连接,说明服务端的账号、授权规则没有问题,CLI侧的报错完全是客户端连接层的问题。
- 不用纠结DSN里把localhost改成127.0.0.1无效的问题:socket、环境变量、库版本的问题会同时影响TCP和socket两种连接模式,不是host名配置的问题。
内容的提问来源于stack exchange,提问作者faelv
相关产品推荐
相关产品推荐

