核心问题是hostname配置错误:必须填docker-compose.yml中定义的MySQL服务名(如db),不可用localhost或127.0.0.1;同时需授权用户允许'%'访问、bind-address=0.0.0.0、认证插件设为mysql_native_password,并通过.env动态注入DB_HOST。

ThinkPHP 数据库配置在 Docker 环境下失效,核心问题不是密码或端口错,而是数据库地址写成了 localhost 或 127.0.0.1——这会让 PHP 容器尝试连接自己内部(空)的 MySQL,而不是同网络下的真实数据库服务。
hostname 必须填服务名,不是 localhost
Docker Compose 中 MySQL 服务怎么定义,PHP 就怎么连:
- 如果
docker-compose.yml里写的是services: db:,那么 ThinkPHP 的database.php(或.env中的DB_HOST)就填 db - 若服务名为
mysql8,则 hostname 就是 mysql8,大小写必须完全一致 -
localhost、127.0.0.1、host.docker.internal都不可靠——尤其在 Linux 生产环境或多容器网络中,它们可能根本解析失败或指向错误目标
MySQL 用户权限要允许容器网段访问
报错 Access denied for user 'root'@'172.20.0.3' 不是密码错了,是账号没授权给容器 IP:
- 进 MySQL 容器执行:
CREATE USER 'app'@'%' IDENTIFIED BY 'your_pass'; - 再执行:
GRANT ALL ON your_db.* TO 'app'@'%'; FLUSH PRIVILEGES; - 避免直接用
root@'%',生产环境建议限定子网,如'app'@'172.20.0.%' - MySQL 8.0+ 默认认证插件为
caching_sha2_password,PHP 7.4 以下版本不兼容,建用户时显式指定:IDENTIFIED WITH mysql_native_password BY 'your_pass'
用 .env 动态注入,别硬编码在 database.php 里
把敏感和环境相关配置抽离到 .env,更安全也更易切换:
- ThinkPHP 6/8 默认读取
.env,设DB_HOST=db、DB_PORT=3306、DB_USERNAME=app等 - 确保
.env文件被挂载进容器(如volumes: - ./env.docker:/var/www/.env),且不提交到 Git - 若用 Docker Compose,也可直接在
environment:下写变量,但推荐统一走.env,逻辑更清晰
加健康检查 + 启动等待,防 MySQL 没就绪
depends_on 只等容器启动,不等 mysqld 能响应 SQL。必须主动等:
- 在 MySQL 服务块加
healthcheck,例如用mysqladmin ping -h localhost -u root -p$MYSQL_ROOT_PASSWORD - PHP 容器的入口脚本(如
entrypoint.sh)里加重试逻辑:until mysqladmin ping -h db -u app -papp_pass --silent; do sleep 2; done - ThinkPHP 自身无连接重试机制,这部分必须由运维层兜底
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











