“Connection refused”错误表明TCP连接被服务器主动拒绝,根本原因不是认证或权限问题,而是目标地址和端口无响应,常见于MySQL服务未启动、DATABASE_URL中host/port配置错误、防火墙或Docker网络隔离。

Connection refused 错误说明服务根本没通
看到 SQLSTATE[HY000] [2002] Connection refused,基本可以确定不是认证或权限问题,而是 TCP 层连不上——目标地址和端口压根没响应。常见原因就三个:mysqld 没启动、DATABASE_URL 里的 host/port 写错、防火墙或 Docker 网络隔离拦住了。
先用命令行验证底层连通性:mysql -h 127.0.0.1 -P 3306 -u root -p。能连上,说明数据库服务正常,问题出在 Symfony 配置;连不上,就别折腾 .env 了,先查 systemctl status mysql 或 docker ps | grep mysql 看服务状态。
DATABASE_URL 中 localhost 和 127.0.0.1 的区别很关键
本地开发时,DATABASE_URL=mysql://user:pass@localhost:3306/dbname 看似合理,但 MySQL 默认对 localhost 使用 Unix socket 连接,而 Symfony + PDO 走的是 TCP。如果 socket 文件路径不对(比如 Alpine 镜像里默认没挂载),就会报 No such file or directory。
- 统一改用
127.0.0.1:避免 socket 路径歧义,强制走 TCP - 确认端口真实监听:
ss -tlnp | grep :3306,看是不是 mysqld 在监听127.0.0.1:3306,而不是127.0.0.1:3307或只监听::1 - Docker 场景下,host 不能写
localhost:容器内localhost指自己,不是宿主机;得用宿主机 IP(如172.17.0.1)或 Docker 网络别名(如host.docker.internal)
wait_timeout 导致空闲连接被 MySQL 主动断开
Symfony 6.1 默认复用 Doctrine 连接,但如果请求间隔超过 MySQL 的 wait_timeout(默认 8 小时),下次再用这个连接就会触发 Lost connection to MySQL server during query。这不是 Symfony 断的,是 MySQL 先关的。
解决办法不是调高 timeout,而是让 Doctrine 主动检测连接有效性:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 在
config/packages/doctrine.yaml里加健康检查:options: {PDO::ATTR_ERRMODE: PDO::ERRMODE_EXCEPTION, PDO::ATTR_PERSISTENT: false}(禁用持久连接) - 更稳妥的做法是启用连接验证:在
DATABASE_URL后追加&serverVersion=8.0&connect_timeout=5,并确保 Doctrine 配置中doctrine.dbal.options包含PDO::ATTR_TIMEOUT - 若用连接池(如 Swoole 或 RoadRunner),必须配置 ping-on-borrow,否则复用失效连接是必然的
MySQL 8.0+ 的 caching_sha2_password 认证插件不兼容
PHP 8.1+ 默认支持 caching_sha2_password,但某些旧版 PDO 或 Alpine 镜像里的 pdo_mysql 扩展可能不带对应逻辑,连 MySQL 8.0+ 会静默失败或报 Access denied,且无明确错误提示。
快速验证方式:用 mysql -u user -p -h 127.0.0.1 能连,但 Symfony 死活连不上,大概率是这个原因。
临时解法(开发环境):
- 进 MySQL 执行:
ALTER USER 'your_user'@'%' IDENTIFIED WITH mysql_native_password BY 'your_pass'; - 刷新权限:
FLUSH PRIVILEGES; - 确保
DATABASE_URL用户是该账号,不是 root
长期方案是升级 PHP 扩展或换用官方 MySQL 8.0 镜像,并确认 php -m | grep pdo_mysql 输出里没有警告。
最常被忽略的点:Doctrine 连接参数里 serverVersion 缺失或写错,会导致方言解析异常,进而让连接复用逻辑出错——看起来像“断开”,其实是查询执行阶段崩溃后连接被丢弃。务必核对 DATABASE_URL 中的 serverVersion 和实际 MySQL 版本完全一致。

















