
本文详解Docker化Laravel项目中控制器内MySQL连接被拒(SQLSTATE[HY000] [2002] Connection refused)的根本原因——服务间网络通信误用宿主机地址,并提供完整、可落地的配置修正与最佳实践。
本文详解docker化laravel项目中控制器内mysql连接被拒(`sqlstate[hy000] [2002] connection refused`)的根本原因——服务间网络通信误用宿主机地址,并提供完整、可落地的配置修正与最佳实践。
在Docker容器化环境中,127.0.0.1 或 localhost 永远指向当前容器自身,而非宿主机或其他服务容器。这是导致你遇到“tinker 和 migrate 正常,但控制器报错”的核心症结:Artisan 命令通过 docker-compose exec main ... 在 main 容器内执行,此时 127.0.0.1:4306 无法访问 db 容器(因为 db 并未监听 main 容器的回环接口);而 php artisan serve 启动的 Web 请求同样运行在 main 容器内,因此复现相同错误。
✅ 正确解法是:在容器内部,必须使用 Docker Compose 定义的服务名作为数据库主机地址。Docker 内置 DNS 会自动将服务名(如 db)解析为对应容器的 IP。
请按以下步骤修正:
1. 修改 .env 文件(关键!)
将数据库主机从 127.0.0.1 改为服务名 db,端口恢复为容器内暴露端口 3306(非映射端口 4306):
DB_CONNECTION=mysql DB_HOST=db # ← 必须改为服务名,不是 127.0.0.1 或 localhost DB_PORT=3306 # ← 使用 db 容器内部端口,非宿主机映射端口 DB_DATABASE=main DB_USERNAME=admin DB_PASSWORD=admin DB_ROOT_PASSWORD=root # 补充:.env 中建议添加此项以匹配 MySQL 配置
⚠️ 注意:
MYSQL_ROOT环境变量在官方 MySQL 镜像中无效,应使用MYSQL_ROOT_PASSWORD(你已在docker-compose.yml中正确定义,但.env中未同步使用,可能导致迁移失败)。
2. 修正 docker-compose.yml 中的 MySQL 配置
你的 MYSQL_USER 和 MYSQL_PASSWORD 设置正确,但 MYSQL_ROOT 是无效键名,需删除并确保 MYSQL_ROOT_PASSWORD 存在且与 .env 中的 DB_ROOT_PASSWORD 逻辑一致(虽 Laravel 不直接使用它,但 php artisan migrate 若需 root 权限建库则依赖此值):
db:
platform: linux/x86_64
image: mysql:8.0
environment:
MYSQL_DATABASE: main
MYSQL_USER: admin
MYSQL_PASSWORD: admin
MYSQL_ROOT_PASSWORD: root # ← 正确键名,保留此项
volumes:
- ./storage/dbdata:/var/lib/mysql
ports:
- "4306:3306" # ← 宿主机映射,仅用于本地 CLI 连接(如 TablePlus),不影响容器间通信3. 重启服务并验证
# 重建并启动(确保新 .env 生效) docker-compose down docker-compose up -d --build # 进入 main 容器验证数据库连通性 docker-compose exec main sh -c "apk add mysql-client && mysql -h db -u admin -padmin main -e 'SELECT 1;'" # 应输出:+---+\n| 1 |\n+---+ # 重新生成密钥并迁移(可选,确保配置生效) docker-compose exec main php artisan key:generate docker-compose exec main php artisan migrate:fresh
4. (进阶)推荐:移除 php artisan serve,改用 Nginx + PHP-FPM
你当前 main 服务基于 php:8.1-fpm-alpine 却运行 artisan serve(内置 PHP Web Server),这不符合生产就绪实践,且易引发静态资源、重写规则等问题。建议拆分为标准三层:
-
app: 构建 PHP-FPM 容器(你的当前main) -
web: Nginx 容器,fastcgi_pass app:9000 -
db: MySQL 容器(保持不变)
这样不仅更贴近真实部署架构,也彻底规避 artisan serve 的调试局限性。
? 总结一句话:Docker 容器网络中,服务发现靠服务名,不靠 localhost;.env 中的 DB_HOST 必须与 docker-compose.yml 中的 services.<name></name> 严格一致——这是所有 Laravel Docker 化项目最常见、最高频的“连接拒绝”根源。修正后,控制器查询、API 接口、队列任务等全链路数据库操作将立即恢复正常。


















