抢救ibdata1的前提是mysqld主进程仍在运行且持有已unlink的句柄,需用ps aux | grep mysqld定位pid,再通过ls -l /proc/pid/fd/ | grep ibdata1确认存在“(deleted)”标记;若未见该标记,则进程已终止,ibdata1实质丢失不可恢复。

能抢救,但窗口期极短——只要 mysqld 进程还在跑,ibdata1 就还活着,只是目录项被 unlink 了。
确认 mysqld 进程是否仍在运行且持有句柄
这是抢救的前提,错过就永远失效。别猜,直接查:
- 用
ps aux | grep mysqld找主进程 PID(排除mysqld_safe或子线程) - 执行
ls -l /proc/<code>PID/fd/ | grep ibdata1,必须看到类似3 -> /var/lib/mysql/ibdata1 (deleted)的输出 - 如果没看到
(deleted),说明进程已重启或被 kill,ibdata1实质丢失,跳过本流程
从 /proc/PID/fd 下拷出 ibdata1 并安全恢复
不能直接覆盖原路径,也不能等 MySQL 自己刷盘——buffer pool 里可能有未落盘的脏页,需先冻结写入:
- 立刻执行
SET GLOBAL innodb_fast_shutdown = 0(让 InnoDB 完全刷干净 redo 和 buffer pool) - 再用
cp /proc/<code>PID/fd/3 /var/lib/mysql/ibdata1.recovered 拷出(数字 3 来自上一步ls -l输出中的 fd 编号) - 立即
chown mysql:mysql /var/lib/mysql/ibdata1.recovered,然后mv /var/lib/mysql/ibdata1.recovered /var/lib/mysql/ibdata1 - 最后
systemctl restart mysql—— 注意:重启前确保ib_logfile*也完好;若它们也被删了,得一并从/proc/<code>PID/fd/ 拷回
为什么不能跳过 innodb_fast_shutdown = 0 直接拷?
因为 ibdata1 不只存数据字典和 undo log,还承载着活跃事务的回滚段、系统表空间头信息等。如果 buffer pool 中有未刷盘的页,而你拷的是旧状态的文件,重启后 InnoDB 会校验失败,报 Tablespace is missing 或直接拒绝启动。
常见错误现象:
- 拷完直接重启,MySQL 启动卡在
InnoDB: Starting crash recovery...然后崩溃 - 日志里出现
InnoDB: Error: space id and page no mismatch - 即使启动成功,
SELECT * FROM mysql.innodb_table_stats报错或返回空
抢救失败后唯一可行的退路:重建字典 + 单表导入
如果进程已死,ibdata1 不可逆丢失,但只要你还有完整的 .ibd 和 .frm(或能导出建表语句),仍可逐表恢复:
- 用
mysqlfrm --server=root:pass@localhost:3306 /path/to/table.frm导出建表语句(注意ROW_FORMAT和KEY_BLOCK_SIZE必须严格一致) -
CREATE TABLE后立即执行ALTER TABLE t DISCARD TABLESPACE -
cp t.ibd /var/lib/mysql/dbname/,再chown mysql:mysql /var/lib/mysql/dbname/t.ibd -
ALTER TABLE t IMPORT TABLESPACE—— 此时若报错Error Code: 1812,99% 是权限或ROW_FORMAT不匹配
真正容易被忽略的点是:IMPORT TABLESPACE 要求表结构与 .ibd 文件头部记录的元数据完全一致,包括 COMPACT/DYNAMIC 格式、压缩设置、甚至 MySQL 版本小版本差异都可能导致失败。











