hyperf容器无法访问数据库主因是db_host误配为localhost或127.0.0.1;正确做法是:宿主机mysql用host.docker.internal,同网络数据库容器用服务名,且mysql需监听0.0.0.0并授权%用户。

Hyperf 容器里连不上数据库,90% 是因为 DB_HOST 配置写死了 localhost 或 127.0.0.1 —— 这在容器内指向的是它自己,不是宿主机或另一个数据库容器。
容器内访问宿主机数据库:用 host.docker.internal 而不是 localhost
当你把 MySQL 装在宿主机(比如 Mac/Windows 上的 Docker Desktop,或 Linux 的非 Docker 环境),Hyperf 容器默认无法通过 localhost 访问宿主机服务。Docker 提供了特殊 DNS 名 host.docker.internal 自动解析到宿主机网关。
- 环境变量应设为
DB_HOST=host.docker.internal,而不是localhost - Linux 用户需手动启用(Docker 20.10+ 默认关闭):
docker run --add-host=host.docker.internal:host-gateway ... - 若用
docker-compose.yml,推荐显式声明:extra_hosts: - "host.docker.internal:host-gateway"
-
ping host.docker.internal在容器内能通,才说明 DNS 可用;不通就别硬试
PHP 容器与 DB 容器跨网络通信:必须共用自定义 bridge 网络
两个容器之间靠服务名通信,前提是它们在同一个用户定义的 bridge 网络里。默认 bridge 网络不支持自动 DNS 解析,docker-compose 默认创建的网络是例外,但纯 docker run 不会自动加入。
- 先创建网络:
docker network create app-net - 启动 DB 容器时指定:
--network app-net --name mysql-db - 启动 Hyperf 容器时同样指定:
--network app-net - PHP 代码里连接串用
mysql:host=mysql-db;port=3306,其中mysql-db是容器名,不是 IP - 检查是否生效:
docker exec -it your-hyperf-container ping mysql-db应该通
Hyperf 配置文件中 DB_HOST 不能写死,必须动态判断运行环境
一个配置文件打天下,在容器和本地开发环境都会出问题。Hyperf 的 config/autoload/database.php 里,host 字段应该读取环境变量,且该变量需在不同部署场景下注入正确值。
- 配置写法示例:
'host' => env('DB_HOST', 'localhost'), - 本地开发(CLI 或 PHP-FPM 模式):.env 里设
DB_HOST=127.0.0.1 - Docker Compose 场景:在
docker-compose.yml的environment或env_file中覆盖DB_HOST=mysql-db - K8s 场景:用
ConfigMap注入,或直接用 Service 名作为DB_HOST - 切忌在 config 文件里写
'host' => 'localhost'—— 这会让容器内永远连自己
验证连接是否真通:别只看容器启没起来
容器运行状态正常 ≠ 数据库连接可用。很多问题卡在 DNS 解析、防火墙、MySQL 绑定地址三处。
- 进容器执行:
nc -zv mysql-db 3306(或telnet mysql-db 3306),不通就不是 PHP 代码问题 - MySQL 容器必须监听
0.0.0.0:3306,而非127.0.0.1:3306(查bind-address配置) - 确认 MySQL 用户允许从容器 IP 段登录:
CREATE USER 'app'@'%' IDENTIFIED BY 'xxx'; GRANT ALL ON *.* TO 'app'@'%'; - Hyperf 启动日志里搜
ConnectionException或PDOException,错误信息比“连不上”更有价值
最容易被忽略的是:Hyperf 启动时会预热连接池,如果此时 DB_HOST 解析失败或端口不通,整个服务可能静默失败或延迟报错——不要只看 docker ps 显示 running 就认为没问题。











