必须声明volumes,否则无持久化——mysql 8.0数据默认存于/var/lib/mysql,不挂载则docker-compose down后全丢;推荐命名卷(如mysql_data),安全且跨平台兼容。

docker-compose.yml 必须包含 volumes 声明
不写 volumes 就没有持久化,容器删掉后数据全丢。MySQL 8.0 默认把数据存在 /var/lib/mysql,这个路径必须挂载到宿主机或命名卷,否则每次 docker-compose down 都等于重装。
推荐优先用命名卷(如 mysql_data),比绑定挂载更安全、跨平台兼容性更好:
- 命名卷由 Docker 管理,自动处理权限和 SELinux 上下文(尤其在 CentOS/RHEL 上)
- 不会因宿主机路径不存在或权限错误导致容器启动失败
- 备份迁移时只需
docker volume inspect+tar卷目录,不依赖绝对路径
如果硬要用绑定挂载(比如想直接编辑 .cnf),务必提前 mkdir -p /path/to/conf 并确保属主是 999:999(MySQL 容器内默认用户 uid/gid)。
MYSQL_ROOT_PASSWORD 是唯一必需的环境变量
MySQL 8.0 容器启动时,MYSQL_ROOT_PASSWORD 是强制要求的,漏掉会直接退出,日志里只显示 error: database is uninitialized and password option is not specified。
其他变量如 MYSQL_DATABASE、MYSQL_USER、MYSQL_PASSWORD 全是可选的,但建议一次性配齐,避免后续手动进容器建库建用户:
-
MYSQL_DATABASE=app_db:容器首次启动时自动创建该数据库 -
MYSQL_USER=app_user+MYSQL_PASSWORD=user_pass:自动创建用户并赋予对MYSQL_DATABASE的全部权限 - 密码复杂度需满足 MySQL 8.0 默认策略(至少 8 位,含大小写字母+数字+特殊字符),否则初始化失败
必须显式指定 mysql:8 或 mysql:8.0.4x 镜像标签
mysql:latest 在 2026 年已指向 MySQL 9.x,强行用会导致应用连接报错 Unknown authentication plugin 'caching_sha2_password' 或驱动不兼容。
使用 Python 脚本下载 Docker 镜像并打包为 tar 文件。用户说“下载镜像”“拉取镜像”“pull xxx”“帮我下载 nginx 镜像”等时触发。支持 SOCKS5 代理直连(推荐)和国内镜像站加速两种模式。
生产环境务必锁定小版本,比如 mysql:8.0.42(当前最新稳定 patch),开发环境可用 mysql:8.0 自动获取 8.0.x 最新版,但别用 mysql:8 —— 它虽仍指向 8.0 系列,但部分发行版镜像行为已有差异。
镜像拉取后可快速验证:docker images | grep mysql 输出应含明确 tag,且 CREATED 时间在近 3 个月内。
第一次启动后要等 mysqld 初始化完成再连
容器状态显示 Up 2 seconds 不代表 MySQL 已就绪。MySQL 8.0 初始化要生成系统表、RSA 密钥、重置 root 密码等,通常耗时 10–30 秒。过早连接会报 Can't connect to local MySQL server through socket 或连接被拒绝。
稳妥做法是启动后执行:docker-compose logs -f mysql | grep "mysqld: ready for connections",看到这行才真正可用。或者加健康检查(但非必需):
healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"] timeout: 20s retries: 10
注意:环境变量在 healthcheck 中需双写 $(即 $$MYSQL_ROOT_PASSWORD),否则会被 shell 展开为空。
最易忽略的是初始化期间的权限等待——MySQL 8.0 启动后会先 chown /var/lib/mysql 目录,若挂载卷初始属主不是 999,它会卡住不动,日志停在 Initializing database。此时只能 docker-compose down,手动 chown -R 999:999 /path/to/data(绑定挂载)或删掉命名卷重建(docker volume rm mysql_data)。










