最近在给自己的 Go 项目部署 Docker 环境时,遇到了一个很有意思的问题:MySQL 容器始终无法启动。
整个排查过程涉及 Docker Volume、MySQL 初始化机制、配置文件兼容性等内容,记录下来,希望能帮助后来人少踩坑。
环境
docker-compose.yml:
mysql:
image: mysql:9.7
container_name: mysql
restart: always
environment:
MYSQL_DATABASE: blog
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
ports:
- "3306:3306"
volumes:
- ./mysql-conf/my.cnf:/etc/mysql/conf.d/my.cnf
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 10s
retries: 10
volumes:
mysql-data:
启动:
docker compose up -d
结果报错:
dependency failed to start: container mysql is unhealthy
第一步:查看容器日志
首先查看日志:
docker logs mysql
发现大量报错:
Invalid MySQL server upgrade:
Cannot upgrade from 80027 to 90700
看到这里第一反应是:
难道 Volume 里残留了旧的 MySQL 8.0 数据?
于是检查 Volume:
docker volume ls
发现:
signal-zxh_mysql-data
进一步进入 Volume 查看:
docker run --rm -it \
-v signal-zxh_mysql-data:/data \
alpine sh
查看数据目录:
ls -la /data
结果发现所有文件都是刚刚创建的。
说明:
-
Volume 确实存在
-
但并不是旧数据
因此排除了「数据库升级失败」这个方向。
第二步:继续看最新日志
继续查看最近日志:
docker logs mysql --tail 100
终于发现关键报错:
unknown option '--skip-character-set-client-handshake'
我的 my.cnf 配置如下:
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
skip-character-set-client-handshake
innodb_buffer_pool_size=256M
max_connections=50
performance_schema=OFF
问题就在这里:
skip-character-set-client-handshake
这个参数在 MySQL 9.x 中已经不再支持。
MySQL 启动时读取配置文件,发现未知参数,直接退出。
第三步:删除错误配置
修改配置:
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
innodb_buffer_pool_size=256M
max_connections=50
performance_schema=OFF
删除:
skip-character-set-client-handshake
重新启动:
docker compose down
docker compose up -d
结果仍然失败。
第四步:发现数据库已经损坏
新的日志变成:
Table 'mysql.user' doesn't exist
Table 'mysql.plugin' doesn't exist
The privilege system failed to initialize correctly
这里终于明白了。
原因是:
第一次启动时,由于配置错误,MySQL 在初始化系统表的过程中被中断。
导致:
mysql.user
mysql.plugin
mysql.component
等系统表没有创建完成。
数据库目录进入了「半初始化状态」。
之后即使修复配置,MySQL 也无法继续启动。
第五步:删除 Volume 重新初始化
开发环境没有重要数据,直接删除 Volume:
docker compose down -v
这里的:
-v
非常关键。
它会删除:
signal-zxh_mysql-data
对应的数据卷。
确认删除:
docker volume ls
重新启动:
docker compose up -d
这次成功启动。
查看状态:
docker ps
结果:
mysql Up (healthy)
signal-zxh Up
总结
这次排查过程让我重新认识了一件事:
工程问题往往不是靠记忆解决,而是靠排查解决。
整个思路其实非常简单:
发现现象
↓
查看日志
↓
提出假设
↓
验证假设
↓
排除错误方向
↓
找到根因
↓
修复问题
最终根因:
-
MySQL 9.7 不再支持
skip-character-set-client-handshake -
第一次启动时初始化被中断
-
数据卷中留下半初始化数据库
-
删除 Volume 后重新初始化解决