Connection timed out不是网络不通,而是TCP握手卡住报错,因PHP容器发出SYN但未收到MySQL容器的SYN-ACK,常见于Docker bridge网络MTU不匹配或MySQL bind-address配置为127.0.0.1导致SYN被静默丢弃。

为什么Connection timed out不是网络不通,而是TCP握手卡住
报错 SQLSTATE[HY000] [2002] Connection timed out 表明 PHP 容器发出了 TCP SYN 包,但没收到 MySQL 容器的 SYN-ACK 响应——这通常不是防火墙拦截(那种会直接报 Connection refused),而是网络栈在中间某层丢包或延迟过高。Docker 默认 bridge 网络在某些宿主机(尤其是启用了 IPv6、启用了 systemd-resolved 或 MTU 不匹配的云服务器)上容易触发此问题。
- 常见诱因:宿主机网卡 MTU 为 1500,但 Docker bridge 默认用 1500,而部分云厂商虚拟网卡实际有效 MTU 是 1450~1460,导致 TCP 分片失败
- 现象特征:MySQL 容器
docker ps显示运行中,docker logs无错误,telnet mysql-server 3306在 PHP 容器内超时,但在宿主机上能通 - 验证方式:进入 PHP 容器执行
ping -c 3 mysql-server(通)+nc -zv mysql-server 3306(超时),基本可锁定为 TCP 层问题
改用host网络模式快速验证是否是 bridge 问题
不改代码、不调配置,仅换网络模式就能确认是不是 Docker 网络栈的问题。注意:host 模式仅用于临时诊断,不可用于生产。
- 启动 PHP 容器时加
--network host,同时把DB_HOST改成127.0.0.1(因为此时容器共享宿主机网络命名空间) - 若此时连接成功,说明确实是 bridge 网络的 MTU 或 iptables 规则问题;若仍超时,则问题在 MySQL 配置、用户授权或端口映射
- ⚠️ 注意:
host模式下不能用容器名(如mysql-server)作 host,必须用127.0.0.1或宿主机真实 IP
调整 Docker bridge 网络的mtu值(永久生效)
Docker daemon 启动时默认创建的 docker0 网桥 MTU 固定为 1500,但很多环境需要主动下调。这不是“优化”,而是对底层网络的适配。
MiniMax 图片理解 + 网络搜索 MCP 工具。适配 Docker 环境(极空间等),支持图片 OCR 识别、图像内容理解、网络搜索。API Key 安全存储在本地 credentials 文件,不暴露在代码中。
- 编辑
/etc/docker/daemon.json,加入"mtu": 1450(从 1450 开始试,逐步加到 1490,直到nc -zv mysql-server 3306成功) - 重启 Docker:
sudo systemctl daemon-reload && sudo systemctl restart docker - 重建网络(关键):
docker network rm bridge && docker network create --driver bridge --subnet=172.18.0.0/16 bridge—— 默认 bridge 网络被删后,Docker 会按新 daemon 配置重建 - 重新运行 MySQL 和 PHP 容器(必须重建,旧容器仍绑定旧 bridge)
mysql-server容器必须监听0.0.0.0:3306而非127.0.0.1:3306
MySQL 默认配置文件里 bind-address = 127.0.0.1 是安全设置,但在 Docker 中它会让 MySQL 只接受来自本容器 loopback 的连接,拒绝所有跨容器 TCP 请求——哪怕网络通畅,也会表现为超时(因 SYN 被静默丢弃)。
立即学习“PHP免费学习笔记(深入)”;
- 检查 MySQL 容器内配置:
docker exec mysql-server grep bind-address /etc/mysql/my.cnf - 正确做法:启动时覆盖 bind-address,例如
docker run -e MYSQL_ROOT_PASSWORD=xxx -d --name mysql-server -p 3306:3306 mysql:8.0 --bind-address=0.0.0.0 - 或者挂载自定义配置文件,在
[mysqld]段写bind-address = 0.0.0.0,并确保skip-networking未启用 - 验证:进容器执行
ss -tln | grep :3306,输出应含*:3306,而非127.0.0.1:3306
MTU 和 bind-address 是两个最常被忽略的硬性条件,缺一不可。很多人调了 MTU 却忘了改 MySQL 监听地址,或反之——结果反复折腾网络模式,其实只差一步。


















