sqlstate[hy000] [2002] 错误90%是主机名解析失败,非密码或端口问题;需在当前执行环境(phpunit、console、web)中用ping或nslookup验证database_url中的host是否可解析,区分docker内外网络差异。

先看错误类型,再决定排查路径:SQLSTATE[HY000] [2002] 或 SQLSTATE[08006] 这类报错,90% 不是密码错、端口关、服务停,而是主机名根本解析失败。
查 DATABASE_URL 中的 host 是否能在当前执行环境解析
PHPUnit 测试、console 命令、Web 请求,三者运行环境可能完全不同——host.docker.internal 在 Docker Desktop(macOS/Windows)上可用,但在 Linux 宿主机默认不存在;database 这个名字只在 Docker 网络内有效,本地 CLI 执行时完全不可达。
- 在终端直接运行
ping database或nslookup database,如果报Name or service not known,说明解析失败,别急着改密码 - 确认当前命令在哪跑:
php ./vendor/bin/phpunit是本地 PHP 进程,docker-compose run --rm app php bin/console才是容器内进程 - 检查
.env和.env.test是否被正确加载:运行php bin/console debug:container --parameter=env(DATABASE_URL),看输出是否含预期 host - Linux 用户若想用 host.docker.internal,需手动在
/etc/docker/daemon.json加"extra_hosts": ["host.docker.internal:host-gateway"]并重启 docker
验证数据库服务是否真在监听且可连通
解析成功 ≠ 能连上。MySQL/PostgreSQL 容器启动后,可能因初始化延迟、权限限制或 bind-address 配置导致拒绝连接。
- 进数据库容器内部测试:
docker-compose exec database mysql -u root -proot -e "SELECT 1"(MySQL)或psql -U symfony -d app_my_ELS -c "SELECT 1"(PostgreSQL) - 从 app 容器里连:
docker-compose exec app ping database→ 成功后再试docker-compose exec app mysql -h database -u root -proot -e "SELECT 1" - 检查数据库配置是否允许远程连接:MySQL 的
bind-address = 0.0.0.0,PostgreSQL 的pg_hba.conf有host all all 0.0.0.0/0 md5 - 确认端口映射正确:
docker-compose port database 3306输出应为0.0.0.0:3306或具体宿主机 IP
区分 APP_ENV=test 时的自动库名后缀行为
Symfony 测试环境会强制把 DATABASE_URL 里的数据库名追加 _test 后缀(如 app → app_test),但不会自动创建该库,也不会跳过连接校验。
- 错误现象:
SQLSTATE[42000] [1049] Unknown database 'app_test',说明连接成功了,只是库不存在 - 解决方式二选一:
mysql -h host.docker.internal -u root -proot -e "CREATE DATABASE IF NOT EXISTS app_test",或在phpunit.xml.dist中禁用隔离:<server name="SYMFONY_DEPRECATIONS_HELPER" value="disabled"></server>并设DB_NAME=app - Doctrine 的
doctrine:database:create命令在 test 环境下默认不生效,它只认APP_ENV=dev或显式传--env=test且配置允许 - 若用 SQLite 做测试库,确保
DATABASE_URL=sqlite:///%kernel.project_dir%/var/test.db路径可写,且var/目录存在
环境变量注入是否被 Docker 或 Symfony 覆盖
Docker Compose 的 environment:、env_file: 和 Symfony 的 .env、.env.local、.env.test 存在优先级和加载时机差异,容易互相覆盖。
- 运行
docker-compose run --rm app env | grep DATABASE_URL,确认容器内实际拿到的值 - 对比
php bin/console debug:container --parameter=env(DATABASE_URL)输出,若不一致,说明 Symfony 没读到容器传入的变量 - 检查
config/bootstrap.php是否调用了Dotenv::createUnsafeLoad(),否则.env.test可能被忽略 - CI 环境中常见陷阱:GitHub Actions 或 GitLab CI 默认不加载 .env.* 文件,必须显式用
export DATABASE_URL=...或通过env:注入
最常被忽略的一点:Doctrine 连接池和连接复用机制会让“第一次失败、后续成功”的假象持续很久——务必清空 var/cache/test/ 再重试,否则旧的连接参数可能被缓存住。











