最近维护的一个基于 Docker 部署的 MySQL 5.7 服务突然无法启动,导致业务中断。查看日志发现是一连串的致命错误,提示系统权限表丢失。
面对这种数据库起不来、系统表损坏的情况,当务之急不是“完美修复环境”,而是先把数据导出来。本文记录了从报错分析到进入“救援模式”并成功导出数据的完整过程。
一、 故障现象
容器启动后立即退出,处于 Restart Loop(无限重启)状态。查看 Docker 日志:
docker-compose logs -f db
关键报错信息如下:
... mysqld: Out of memory (Needed 4294967200 bytes) ... [ERROR] Fatal error: Can't open and lock privilege tables: File './mysql/columns_priv.MYD' not found (Errcode: 2 - No such file or directory) [ERROR] Fatal: can't initialize grant subsystem - 'File './mysql/columns_priv.MYD' not found' [ERROR] Aborting
二、 问题分析
- OOM (Out of Memory): 日志开头出现了
Out of memory,说明宿主机或容器内存不足,导致 MySQL 进程曾被强制杀掉。 - 文件损坏: 随后出现的
Fatal error: Can't open and lock privilege tables是最致命的。这说明 MySQL 的核心系统库(mysql库)中的权限表文件(如columns_priv.MYD)丢失或损坏。
因为权限表损坏,MySQL 无法验证用户身份,所以无法正常启动。
三、 救援方案
既然正常模式无法启动,我们的目标是:
- 物理备份(防止误操作导致全军覆没)。
- 开启 MySQL 的“跳过权限检查”模式,强行启动。
- 使用
mysqldump导出业务数据。 - 重建干净的数据库实例并导入数据。
四、 操作步骤
第一步:物理文件冷备份(最重要!)
不管能不能修好,先保留案发现场。直接在宿主机上把挂载的卷目录复制一份。
# 假设原来的挂载目录是 /home/volume/wp-bak/db/ cp -r /home/volume/wp-bak/db/ /home/volume/wp-bak/db_backup_raw/
注意:如果后续操作失败,我们还可以尝试从这个 raw backup 中恢复
.ibd文件。
第二步:修改 docker-compose 进入“救援模式”
我们需要修改 docker-compose.yml,给 MySQL 容器加上启动参数,让它忽略权限表并尝试强制恢复。
修改 docker-compose.yml:
services:
db:
image: mysql:5.7
ports:
- "13202:3306"
volumes:
- /home/volume/wp-bak/db/:/var/lib/mysql
# 【新增】添加下面这行 command
command: --skip-grant-tables --innodb_force_recovery=1
restart: always
参数解释:
--skip-grant-tables: 不加载权限表(从而绕过columns_priv.MYD丢失的报错),允许无密码登录。--innodb_force_recovery=1: 让 InnoDB 引擎以只读/低恢复模式启动,忽略部分损坏页,增加启动成功的概率。
第三步:启动并导出数据
应用修改并启动容器:
docker-compose up -d
查看日志确认是否存活:
docker-compose logs -f db # 只要看到 "ready for connections" 或者没有立即退出,就说明救援模式启动成功
进入容器导出数据(无需密码):
# 1. 进入容器 docker exec -it <容器ID或名称> /bin/bash # 2. 确认数据库还在 mysql -u root -e "SHOW DATABASES;" # 3. 导出业务数据库(例如库名叫 wordpress) # 注意:因为开启了 skip-grant-tables,不需要输入密码 mysqldump -u root --default-character-set=utf8mb4 wordpress > /var/lib/mysql/wordpress_rescue.sql
此时,导出的 SQL 文件 wordpress_rescue.sql 已经保存在宿主机的挂载目录下了。
第四步:彻底重建
既然系统表已经损坏,继续使用这个环境是不安全的。建议彻底重建。
- 停止容器:
docker-compose down - 移除旧的数据目录(确保你已经有了第一步的备份和第三步的 SQL 文件!):
rm -rf /home/volume/xiaocaicai-wp-bak/db/* - 去掉
docker-compose.yml中的command行,恢复正常配置。 - 重新启动容器,此时 MySQL 会重新初始化生成全新的数据文件。
- 将刚才导出的
wordpress_rescue.sql导入新数据库。
五、 避坑指南与总结
- 内存限制:这次事故的诱因是 OOM。建议在
docker-compose.yml中给数据库容器加上内存限制(mem_limit),或者增加服务器的 Swap 分区,防止 MySQL 吃光内存被系统 Kill 导致文件损坏。 - 数据备份:定期的逻辑备份(mysqldump)比物理挂载更可靠。可以编写简单的 Shell 脚本每天定时导出 SQL。
- 冷静分析:看到 Fatal Error 不要慌,只要
.ibd(数据文件)还在,就有办法恢复。skip-grant-tables是处理权限相关错误的万能钥匙。
希望这篇记录能帮到同样遇到 MySQL 崩溃的朋友!