Docker 部署 Go 项目时,MySQL 9.7 一直启动失败,我是如何排查的

最近在给自己的 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

总结

这次排查过程让我重新认识了一件事:

工程问题往往不是靠记忆解决,而是靠排查解决。

整个思路其实非常简单:

复制代码
发现现象
↓
查看日志
↓
提出假设
↓
验证假设
↓
排除错误方向
↓
找到根因
↓
修复问题

最终根因:

  1. MySQL 9.7 不再支持 skip-character-set-client-handshake

  2. 第一次启动时初始化被中断

  3. 数据卷中留下半初始化数据库

  4. 删除 Volume 后重新初始化解决