mysql宕机后数据是否丢失取决于redo log完整性及ibdata1、.ibd文件是否损坏;应优先尝试innodb_force_recovery=1~6启动并只读导出数据,而非直接拷贝文件或重启。

MySQL宕机后数据还在不在,先看innodb_force_recovery能不能启动
InnoDB 引擎崩溃后,数据是否“丢”不取决于宕机瞬间,而取决于redo log是否完整、ibdata1和.ibd文件是否损坏。直接强行重启 MySQL 很可能触发崩溃恢复失败,报错类似:Database page corruption on disk or a failed file read 或 Cannot continue operation。这时候别急着删数据目录,先尝试用安全模式启动:
- 在
my.cnf的[mysqld]段下加一行:innodb_force_recovery = 1 - 从 1 试到 6(值越大限制越严),通常
1~3能让 mysqld 启动并允许只读访问 -
innodb_force_recovery ≥ 4会禁用INSERT/UPDATE/DELETE,连DROP TABLE都拒绝——这不是修复手段,只是保命读取 - 一旦能连上,立刻用
mysqldump导出还能访问的库,别等第二次宕机
为什么不能跳过redo log直接拷贝.ibd文件
InnoDB 的崩溃恢复核心依赖redo log(重做日志)把已提交但没写入数据页的修改“重放”一遍。如果宕机时redo log还没刷盘(比如innodb_flush_log_at_trx_commit = 0且刚好断电),那这部分事务确实丢失;但如果redo log完好,仅靠.ibd文件是“半成品”——它可能包含未提交的脏页或缺失最后几条更新。
- 单独复制
test.ibd到另一台实例,大概率报错:Tablespace is missing for table 'test'或InnoDB: Operating system error number 2 in a file operation - 即使强制
ALTER TABLE ... IMPORT TABLESPACE,也会因redo log序列号(LSN)不匹配而失败,错误提示含Invalid LSN - 真正可迁移的是
mysqldump导出的 SQL,或mysqlpump+xtrabackup的一致性快照,不是裸文件
innodb_force_recovery失效时,ibdata1损坏怎么抢救
如果innodb_force_recovery = 6仍无法启动,大概率是共享表空间ibdata1头部元数据损坏(比如前 100 字节被覆盖)。这时redo log本身可能完好,但 InnoDB 找不到校验起点。不要格式化磁盘,先用工具试探性读取:
- 用
strings ibdata1 | head -50看是否还有INFORMATION_SCHEMA或库名残留,有则说明结构未全毁 - 用
hexdump -C ibdata1 | head -20查看开头是否为78 78 78 78(InnoDB 文件头标志),若不是,可能是被覆盖或加密 - 若确认
ibdata1损坏但.ibd文件完好(每个表一个独立文件),可尝试新建实例 +CREATE TABLE LIKE+DISCARD TABLESPACE+IMPORT TABLESPACE恢复单表 - 注意:
IMPORT TABLESPACE要求.ibd的 LSN 和目标实例当前 LSN 接近,否则需用innodb_page_size和innodb_log_file_size完全一致的环境
恢复后必须立刻检查undo log和主从延迟
哪怕成功导出数据,也要警惕两类隐藏问题:一是undo log段损坏导致 MVCC 异常(表现为SELECT返回旧版本或锁等待超时);二是主从复制中断后,relay log里积压的事务可能和恢复后的数据冲突。
- 执行
SHOW ENGINE INNODB STATUS\G,重点看TRANSACTIONS部分是否有ROLLING BACK卡住的事务 - 查
information_schema.INNODB_TRX,确认没有长时间运行的trx_state = RUNNING事务残留 - 如果是主从架构,恢复完主库后,从库不能直接
START SLAVE,要先STOP SLAVE,再用SHOW SLAVE STATUS对比Relay_Master_Log_File和Exec_Master_Log_Pos是否落在主库当前 binlog 范围内 - 最保险的做法:恢复后立即关闭写入,用
pt-table-checksum校验主从一致性,再逐步放开流量
真正难的不是恢复动作本身,而是判断哪部分redo log还可用、哪块ibd其实已经静默损坏——这些没法靠脚本自动识别,得结合error log里最后一行InnoDB: Starting crash recovery之后的 LSN 变化和文件系统时间戳交叉验证。











