看到Database page corruption错误必须立即停写入,而非删文件;此时数据未必全丢,需先定位损坏页,再从innodb_force_recovery=1逐级尝试启动并用mysqldump导出数据,成功后必须重建数据目录而非修复旧目录。

看到 Database page corruption 错误必须立刻停写入
这不是警告,是紧急制动信号。MySQL 在错误日志里打出 Database page corruption on disk 或 failed file read of page [page id: space=XX, page number=YY],说明 InnoDB 已在校验时发现某个 16KB 页(可能在 ibdata1、某个 .ibd 文件,甚至系统表空间)内容异常——磁盘没坏、文件没删错的前提下,数据未必全丢,但继续写入会放大损坏,甚至让还能读的页也变不可恢复。
此时别删文件、别重装、别跑 REPAIR TABLE(InnoDB 根本不支持),更别尝试手动修改页头。唯一合理动作:立即停止应用写入,把实例设为 read_only=ON,准备用 innodb_force_recovery 启动只读模式抢救数据。
innodb_force_recovery 从 1 开始试,别跳级
这个参数不是“修复开关”,而是“绕过检查开关”。它的 1–6 级是严格递进的:值越大,跳过的恢复逻辑越多,风险也越高。官方明确警告:innodb_force_recovery=4 起会永久禁用写操作且可能破坏文件一致性,=6 仅允许读取,且不能保证所有页都可访问。
-
innodb_force_recovery = 1:跳过脏页检查,适合单个索引页损坏,多数轻量损坏在此级就能连上 -
=2:禁用 purge thread,若崩溃由后台清理触发,常能启动 -
=3:跳过事务回滚,未提交事务丢失,但已提交数据通常可导出 -
=4及以上:自动启用read_only=ON,且会跳过 undo 扫描、redo 应用等关键步骤;仅在 1–3 失败时考虑,且必须先在测试环境验证
每次改完配置后必须重启 mysqld,并立刻用 mysql -u root -e "SELECT 1" 验证是否连得上,再查关键表能否 SELECT COUNT(*) ——不要等到 mysqldump 才发现失败。
mysqldump 导出时遇到 Error 2013 怎么办
即使启用了 innodb_force_recovery,mysqldump 仍可能在读到损坏页时断连(报 Error 2013: Lost connection)或卡死。这不是配置问题,而是目标表本身有物理页损坏。
- 先用
SHOW TABLE STATUS LIKE 'table_name'查Data_length和Index_length,值为 0 或明显偏小的表大概率已损坏 - 导出时加
--ignore-table=db_name.corrupt_table排除已知坏表,保主干库 - 对关键但损坏的表,尝试分批读:
SELECT * FROM table_name LIMIT 10000 OFFSET 0,观察在哪一批中断,再调整 OFFSET 绕开(InnoDB 不保证页内行连续,但有时有效) - 避免用
--all-databases一次性导出;按库、按表分开执行更可控,失败也不影响其他数据
注意:mysqlpump 在部分版本中因元数据锁机制可能失败,优先用 mysqldump。
导完必须清掉 innodb_force_recovery 并重建数据目录
这个参数只是临时救命用的,绝不能长期开着运行。它会让 InnoDB 跳过事务一致性保障,后续任何写入(哪怕只是 INSERT 一行)都可能让损坏扩散或产生不可逆的数据错位。
导出完成后,务必做三件事:
- 从配置文件中彻底删除
innodb_force_recovery行,或设回=0 - 停服务,手动清空整个数据目录(如
/var/lib/mysql),包括ibdata1、ib_logfile*、所有.ibd文件 - 用备份重建:初始化新实例 + 导入
mysqldump输出的 SQL,而不是试图“修复旧目录”
最容易被忽略的一点:如果损坏页涉及系统表空间(比如 ibdata1 中的 data dictionary 页),即使你成功导出了用户表,自增 ID、外键约束、存储过程定义等元数据也可能已错乱,重建时需人工校验并补全。


















