PHP 连 Docker MySQL 的关键是容器网络互通,host 应填 MySQL 容器名(如 mysql-db)而非 localhost;需共用自定义网络、配置 bind-address=0.0.0.0、授权 'user'@'%',端口用容器内默认 3306。

PHP 项目要连 Docker 里的 MySQL,关键不是“怎么进容器”,而是让 PHP 进程能通过网络访问 MySQL 容器的端口——Docker 默认不暴露容器内网 IP 给宿主机外进程直接用,得靠容器网络互通或端口映射。
PHP 连接 MySQL 容器时,host 不能写 127.0.0.1 或 localhost
这是最常踩的坑:你在宿主机跑 php script.php,脚本里写 host=localhost,它会去连宿主机的 3306,不是 MySQL 容器的。除非你做了端口映射(如 -p 3306:3306),且确认 MySQL 容器允许外部连接(bind-address = 0.0.0.0、用户有远程权限)。
- 推荐方式是:用 Docker 自建网络 + 容器名当 host —— 比如 MySQL 容器起名为
mysql-db,PHP 容器里就填host=mysql-db - 如果 PHP 是宿主机上的 CLI 或 Apache,又没映射端口,
localhost就完全不通,必须映射 + 开放权限 - Docker Desktop for Mac/Windows 的
host.docker.internal可用于宿主机服务连容器,但 Linux 上默认不支持,需手动加--add-host=host.docker.internal:host-gateway
docker-compose.yml 中必须显式定义 network 并共用
光靠默认 bridge 网络,容器名解析不一定生效;共用自定义网络才能稳定用名字通信。
version: '3.8'
services:
php-app:
image: php:8.2-cli
networks:
- app-net
depends_on:
- mysql-db
mysql-db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: testdb
ports:
- "3307:3306" # 映射到宿主机 3307,避免和本地 MySQL 冲突 networks:
- app-net
networks: app-net: driver: bridge
-
networks块必须顶层定义,且两个服务都加入同一网络 -
ports是可选的——只在需要从宿主机(如浏览器、CLI)访问时才开;PHP 容器连 MySQL 不依赖它 - MySQL 容器启动后,PHP 容器里执行
ping mysql-db或nc -zv mysql-db 3306可验证连通性
PHP PDO / mysqli 连接字符串里的参数要对应容器配置
别硬套本地开发习惯。容器内 MySQL 的 root 密码、数据库名、端口都来自 environment 或镜像默认值。
立即学习“PHP免费学习笔记(深入)”;
- host:填容器名(如
mysql-db),不是127.0.0.1 - port:默认 3306,除非 MySQL 容器改了
my.cnf里的port;不用写宿主机映射后的端口(3307) - user/password:按
MYSQL_ROOT_PASSWORD或建库时创建的用户来设;root 用户默认只允许从%或localhost连,容器间通信走的是内网 IP,所以建用户时得指定'user'@'%' - 示例 PDO DSN:
mysql:host=mysql-db;dbname=testdb;charset=utf8mb4
连不上时优先查这三件事
90% 的连接失败卡在这三个点,比调代码快得多。
- PHP 容器是否和 MySQL 容器在同一个
network下?运行docker inspect看NetworkSettings.Networks - MySQL 容器日志有没有报错?
docker logs mysql-db | tail -20,常见是Access denied for user或Can't connect to local MySQL server(说明 mysqld 没起来) - MySQL 是否监听所有地址?进容器执行
mysql -u root -prootpass -e "SELECT @@bind_address;",结果要是0.0.0.0或*,不是127.0.0.1
真正麻烦的不是语法或命令,是网络拓扑意识——Docker 里没有“本地”这个概念,只有容器名、网络别名、端口映射三层关系。搞不清哪层该用什么地址,就会反复试 localhost、172.x.x.x、host.docker.internal,越试越乱。











