一次典型的 MySQL 故障排查与修复全过程,涵盖登录失败、表崩溃、innodb_force_recovery 救援、坏表剔除与数据恢复等关键操作。
一、问题背景
某业务系统运行多年,数据库使用的是 MySQL 8.0.18,近期在一次服务器重启后,发现无法正常连接数据库,提示:
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
尝试重启 MySQL,过程似乎正常:
sudo service mysql restart # 显示 SUCCESS
但用 mysql -u root -p
登录时依旧提示账号密码错误。开始怀疑是否数据损坏或权限配置有误。
二、排查思路
1. 登录失败:确认密码正确性
-
使用其他账户尝试连接(如 test 用户)。
-
发现部分用户仍可登录,说明 数据库服务本身是正常的 ,但
root
权限或数据可能损坏。
2. 可登录用户访问数据时报错
登录后,执行 SQL 删除某张表时报错:
DROP TABLE imp_index_warn_data; ERROR 1036 (HY000): Table 'tablespace_files' is read only
甚至强制设置参数后依旧失败:
SET GLOBAL innodb_fast_shutdown = 0; DROP TABLE imp_index_warn_data; # 报错 3604,存储引擎无法删除该表
结论:该表已严重崩溃,影响了 InnoDB 正常功能。
三、制定解决策略
目标
-
保住正常表的数据。
-
剔除坏表 imp_index_warn_data。
-
尽量避免数据损失与停机时间。
解决方案路线图
-
使用
innodb_force_recovery
启动数据库。 -
导出除坏表以外的所有数据。
-
停止数据库服务,物理删除坏表相关文件。
-
启动数据库,删除坏表元数据。
-
恢复数据库服务到正常模式。
四、操作步骤详解
步骤 1:修改 my.cnf,启用恢复模式
编辑 /etc/my.cnf
:
[mysqld] innodb_force_recovery = 6
含义:略过大部分恢复步骤并只读启动。仅用于应急,不可长期开启。
保存后重启数据库:
sudo service mysql restart
步骤 2:导出正常表数据
使用 mysqldump
排除坏表:
mysqldump -u root -p --skip-lock-tables i18n_demo > i18n_demo.sql
确保 imp_index_warn_data
未导出。
步骤 3:停止数据库服务,删除坏表文件
sudo service mysql stop
进入数据目录(示例路径如下,具体看你的配置):
cd /usr/local/mysql/mysql-8.0.18/data/i18n_demo
备份坏表相关文件:
mkdir ~/bad_table_backup mv imp_index_warn_data.* ~/bad_table_backup/
步骤 4:重启数据库,清除元数据
重启服务:
sudo service mysql start
登录数据库,清理元数据:
DROP TABLE imp_index_warn_data;
此时应该不会再报错。
步骤 5:导入数据并恢复服务正常
取消 innodb_force_recovery
:
# /etc/my.cnf 中移除或注释: # innodb_force_recovery = 6
重启服务:
sudo service mysql restart
导入之前备份的数据:
mysql -u root -p i18n_demo < i18n_demo.sql
至此,数据库恢复完成!
五、总结与经验教训
✅ 收获
-
理解
innodb_force_recovery
各个级别的作用。 -
掌握 MySQL 启动失败或崩溃时的应急处理手段。
-
明确了"逻辑删除表"与"物理删除文件"的边界和使用时机。
❌ 教训
-
未开启 binlog、没有定期全量备份,是很大风险。
-
某些老旧系统的数据表结构混乱、未做分区或冷热分离,极易出现单表崩溃。
六、附录:常用命令速查
操作 | 命令 |
---|---|
查看服务状态 | sudo systemctl status mysql |
停止 MySQL | sudo service mysql stop |
启动 MySQL | sudo service mysql start |
数据导出 | mysqldump -u root -p db_name > backup.sql |
数据导入 | mysql -u root -p db_name < backup.sql |
如果你也遇到类似问题,记得第一时间备份,并小心操作 innodb_force_recovery
的等级!任何强制操作都要以"可恢复"为前提。