hyperf 项目用域名连接 mysql 失败,90% 是 dns 解析失败或连接池未适配域名场景导致的,不是代码写错;根本原因是 php 进程无法解析域名(如容器内 nslookup 无响应),pdo 尝试连接空地址或 localhost 而报“connection refused”,需通过预解析为 ip 或显式配置 dns 解决。

Hyperf 项目用域名连接 MySQL 失败,90% 是 DNS 解析失败或连接池未适配域名场景导致的,不是代码写错了。
Hyperf 连接 MySQL 域名时 PDOException 报错 “Connection refused”
这通常不是 MySQL 拒绝连接,而是 PHP 进程根本没解析出 IP —— 域名在 CLI 环境下可能无法解析(尤其容器或 Docker Compose 中),gethostbyname() 返回空或超时,最终 PDO 尝试连接 localhost 或空地址。
- 检查是否真能解析:在 Hyperf 容器内执行
nslookup your-mysql-host.example.com,若无响应或超时,说明 DNS 不通 - Docker 场景下,默认使用宿主 DNS,但某些网络模式(如
host或自定义 bridge)会绕过它;可在docker-compose.yml中显式加dns配置,例如:dns: ["8.8.8.8", "114.114.114.114"] - Hyperf 的
mysql://DSN 不支持自动重试 DNS,一旦解析失败就直接抛异常,不会 fallback 到 IP - 临时验证方式:把域名换成对应 IP 写进
config/autoload/databases.php,如果连上了,基本锁定是 DNS 问题
pool.max_connections 设太高反而加剧域名解析失败
高并发下大量连接同时触发域名解析,容易触发 glibc 的 resolv.conf 限制或 DNS 服务器限流,表现为部分请求成功、部分报 Connection timeout,日志里夹杂 php_network_getaddresses: getaddrinfo failed。
- 默认
pool.max_connections是 10,生产环境调到 50–100 时,必须确认 DNS 服务扛得住 —— 尤其是私有 DNS 或 CoreDNS 在 K8s 中未配置maxConcurrentQueries - 建议先压测 DNS:用
dig +short your-mysql-host.example.com并发跑 100 次,看失败率和延迟 - 更稳妥的做法是:在部署阶段用
envsubst或启动脚本把域名预解析成 IP,注入到 Hyperf 配置中,避免运行时解析 - 不要依赖
pool.max_idle_time缓解该问题 —— 空闲连接不参与 DNS 查询,但新连接仍会查
MySQL 用户授权写 'user'@'%' 仍连不上?检查 host 字段是否被 DNS 反解污染
MySQL 在认证时,会对客户端 IP 做反向 DNS 查询(skip_name_resolve=OFF 时),若你的域名解析不稳定,MySQL 可能拿到一个不可信的 hostname(比如 unknown.192.168.1.100),然后匹配 'user'@'unknown.192.168.1.100' 而非 'user'@'%',导致权限拒绝。
- 登录 MySQL 执行
SELECT USER(), CURRENT_USER();,对比两个结果 —— 若CURRENT_USER()显示 hostname 而非 IP,说明开启了 hostname 匹配 - 临时解决:在 MySQL 配置文件
[mysqld]段加skip_name_resolve = ON,重启 mysqld(注意:开启后不能用 hostname 授权,只能用 IP 或%) - 长期方案:确保 DNS 正向/反向一致,或直接在授权语句中明确指定客户端真实 IP 段,例如
GRANT ... TO 'user'@'192.168.10.%' - Hyperf 日志里若出现
Access denied for user 'xxx'@'some-hostname',基本就是这个原因
域名连接看着方便,但在 Hyperf 这类常驻进程框架里,它把 DNS 变成了单点风险。最稳的方式永远是:CI/CD 阶段解析一次,固化为 IP 注入配置,而不是靠运行时碰运气。











