“tablespace is missing for table”错误主因是.ibd文件与内存表定义不匹配,需同时满足:用flush tables for export导出(含元数据校验)且目标表结构完全一致(包括row_format、字符集、列序等)。

ALTER TABLE ... IMPORT TABLESPACE 不是“拷过去就能用”的操作。它对文件来源、表结构、MySQL版本和元数据一致性有硬性要求,缺一不可。直接 cp .ibd 过去再 IMPORT,99% 失败。
为什么 IMPORT TABLESPACE 总报 “Tablespace is missing for table”
这个错误不是说 .ibd 文件没找到,而是 MySQL 在内存里找不到匹配的表定义,或校验失败。核心原因只有两个:
• .ibd 不是用 FLUSH TABLES t FOR EXPORT 生成的(缺少 .cfg 元数据 + 表空间冻结状态)
• 目标库建的表结构和源表不一致:比如 ROW_FORMAT、KEY_BLOCK_SIZE、字符集、列顺序、隐藏字段(如 FTS_DOC_ID)、甚至 STATS_PERSISTENT 隐式参数都必须完全相同
• MySQL 8.0 虽不再依赖 .cfg 恢复列定义,但仍会读它做 space_id 和 page_no 校验——没 .cfg 就报 ERROR 1812: Tablespace file not found,哪怕 .ibd 就在旁边
从崩溃/误删实例抢救出的 .ibd,没有 .cfg 怎么办
不能走 IMPORT TABLESPACE 流程。此时 .ibd 是“裸文件”,没有导出时的元数据快照,MySQL 无法安全加载。
• 必须停写、停止 MySQL 服务,防止文件被覆盖
• 使用 innodb_force_recovery 启动(级别 1–6 逐级试),配合 mysqldump 导出可见数据
• 或用开源工具解析二进制结构:如 ibd2sdi(MySQL 自带,可提取部分表定义)、Percona Data Recovery Tool for InnoDB(需手动提供表结构 SQL)、undrop-for-innodb(依赖 mysql-systemd 等辅助脚本,对 ROW_FORMAT=Dynamic/Compressed 支持有限)
• 若文件系统是 ext3/ext4,且删除后未大量写入,可用 extundelete 尝试找回原 .cfg 文件——但成功率极低,别抱希望
MySQL 8.0 下 DATA DIRECTORY + IMPORT 的实操陷阱
MySQL 8.0.23+ 支持 CREATE TABLE ... DATA DIRECTORY = '/path/to/t',但和 IMPORT TABLESPACE 混用极易翻车:
• .cfg 必须和 .ibd 放在同一目录,且文件名严格为 t.cfg(不能是 db/t.cfg 或带时间戳)
• DATA DIRECTORY 路径需被 secure_file_priv 或 innodb_directories 显式允许,否则启动报错
• 执行 ALTER TABLE t DISCARD TABLESPACE 后,MySQL 会删掉原 .ibd,但不会动 .cfg——你得自己确认目标目录下是否残留旧 .cfg,否则导入时校验失败
• 即使路径、文件名、权限全对,若源库是 5.7、目标是 8.0,space_id 格式差异仍可能导致 ERROR 1812
真正能跑通的最小闭环流程
前提是:你有冷备份的 .ibd + .cfg,且知道源表结构。
• 在目标库执行 SHOW CREATE TABLE 原样建表(不要手写,尤其注意 ENGINE=InnoDB ROW_FORMAT=Dynamic STATS_PERSISTENT=1 这类隐式项)
• 执行 ALTER TABLE t DISCARD TABLESPACE(删掉目标 .ibd,保留字典)
• 把备份的 .ibd 和 .cfg 拷到目标表对应目录(datadir/db/t.ibd),确保属主是 mysql:mysql,权限 640
• 执行 ALTER TABLE t IMPORT TABLESPACE
• 立即查 SELECT COUNT(*),再 SELECT * LIMIT 1 看是否报 ERROR 2013(说明页校验失败,大概率是 .cfg 版本不匹配或 FLUSH ... FOR EXPORT 没执行)
关键点不在“怎么导入”,而在于“怎么证明这张表的定义和那个 .ibd 是一对”。所有失败,几乎都卡在定义对不上——哪怕只差一个空格。











