docker-compose up -d 成功不等于 Laravel 可用,常见 Class 'App\Models\User' not found、SQLSTATE[HY000] [2054]、Connection refused 等报错,根源在于环境契约未对齐:DB_HOST 必须设为 db(非 localhost),MySQL 8 需配置 MYSQL_DEFAULT_AUTHENTICATION_PLUGIN=mysql_native_password,app 服务需指定 user: "${UID:-1000}:${GID:-1000}" 解决挂载权限问题,且首次创建项目后必须 docker-compose up -d --build app 以确保 autoload 生效。

docker-compose up -d 能跑起来,不代表 Laravel 真正可用——常见报错如 Class 'App\Models\User' not found、SQLSTATE[HY000] [2054]、Connection refused,几乎全因环境契约没对齐,不是命令没敲对。
docker-compose.yml 里 DB_HOST 必须写成 db,不能写 localhost
容器间通信走的是 Docker 内置 DNS,localhost 在 PHP 容器里指向自己,不是 MySQL 容器。官方镜像默认服务名即主机名,所以 DB_HOST=db 才能解析到 MySQL 容器的 IP。
-
docker-compose.yml中 MySQL 服务必须命名为db(或对应修改.env中的DB_HOST) - 别在
.env里硬写127.0.0.1或localhost,那在容器内永远连不上 - 如果改了服务名(比如叫
mysql8),就得同步改DB_HOST=mysql8
php artisan migrate 报 SQLSTATE[HY000] [2054] 是 MySQL 8 认证插件不兼容
MySQL 8 默认用 caching_sha2_password,但 PHP 7.4–8.1 的 mysqlnd 驱动老版本不认这个插件,直接拒绝连接。
- 最稳解法:在
docker-compose.yml的db服务里加 environment:MYSQL_DEFAULT_AUTHENTICATION_PLUGIN=mysql_native_password - 别指望靠升级 PHP 解决——Laravel 9/10 项目常锁 PHP 8.1,而 mysqlnd 适配 caching_sha2_password 要 8.2+,升级 PHP 可能引发其他扩展兼容问题
- 验证方式:进 MySQL 容器执行
SELECT host, user, plugin FROM mysql.user WHERE user='homestead';,确认 plugin 是mysql_native_password
src/ 目录挂载后 vendor 和 storage 权限经常 777 失效
Docker 容器以 root 运行,宿主机用户 UID 通常不是 0,导致挂载进来的 storage 和 vendor 文件属主错乱,php artisan view:clear 或日志写入失败。
- 在
docker-compose.yml的app服务里显式指定user: "${UID:-1000}:${GID:-1000}",并确保启动前执行export UID=$(id -u)、export GID=$(id -g) - 别依赖
chmod -R 777 storage——容器重启后权限重置,且不安全 - 如果用 WSL2,注意 Windows 用户 UID/GID 映射可能不准,建议在 WSL 内手动
id查值再 export
第一次 docker-compose run --rm composer create-project 后,得立刻重 build app 服务
因为 composer create-project 生成的代码是挂载进容器的,但 PHP 镜像构建时 WORKDIR 下原本是空的;不 rebuild,artisan 命令会找不到 autoload.php。
- 顺序必须是:
docker-compose run --rm composer create-project laravel/laravel .→ 修改.env→docker-compose up -d --build app - 跳过
--build会导致 PHP 容器内/var/www/html仍是旧镜像里的空目录,哪怕文件已挂载成功 - 如果已启动过,先
docker-compose down再up -d --build,避免缓存干扰
docker-compose up -d 成功就万事大吉——其实只是网络通了,PHP 没读到正确配置,MySQL 插件不认人,文件权限不让写,autoload 还没加载。每一步都得验,而不是等报错才回头查。


















