必须停止mysql服务才能安全拷贝datadir,否则innodb因redo log、buffer pool与磁盘文件状态不一致,恢复后将报tablespace is missing或直接崩溃;需用mysqladmin shutdown或systemctl stop mysqld彻底停服,并确认无残留进程和pid文件。

物理拷贝前必须停掉 MySQL 服务
直接拷贝 datadir 目录的前提是源实例完全停止,否则 InnoDB 的 redo log、buffer pool 状态与磁盘文件不一致,恢复后大概率报错 Tablespace is missing for table 或直接崩溃。别信“只读状态下能拷”,MySQL 没有真正意义上的只读物理一致性快照机制。
操作要点:
- 用
mysqladmin shutdown或systemctl stop mysqld停服务,确认ps aux | grep mysqld无残留进程 - 检查
pid_file是否已删除(如/var/run/mysqld/mysqld.pid),残留 pid 文件会导致新实例拒绝启动 - 若源库启用了
innodb_file_per_table=OFF,整个ibdata1必须完整拷贝,不能只搬单个库目录
目标机需严格匹配 MySQL 版本和配置
5.7 拷到 8.0 上基本失败;小版本差异(如 5.7.28 → 5.7.35)也可能因页格式或系统表结构变更导致 InnoDB: Upgrade after a crash is not supported。不是“版本相近就能用”。
关键检查项:
- 运行
mysqld --version确认主版本号、次版本号完全一致 - 比对源/目标的
my.cnf中以下参数:innodb_page_size、innodb_log_file_size、character_set_server、collation_server - 目标机
datadir目录权限必须为mysql:mysql,且禁止存在旧的ibdata1、ib_logfile*文件(会触发 recovery 流程,破坏拷贝数据)
拷贝后首次启动必须跳过权限校验并强制重建系统表
直接启动会卡在 mysqld: Can't find file: './mysql/plugin.frm' —— 因为 mysql 系统库的 frm / ibd 文件是随初始化生成的,物理拷贝后与目标机的 server_uuid、auto_increment 等元信息冲突。
正确做法:
- 先用
mysqld --initialize-insecure --datadir=/path/to/datadir初始化一次空系统库(仅生成基础文件,不设 root 密码) - 再删掉刚生成的
mysql/目录,把源拷来的完整mysql/替换进去 - 启动时加参数:
mysqld --skip-grant-tables --skip-networking,避免权限表加载失败阻塞 - 连上后立即执行
FLUSH PRIVILEGES;,再ALTER USER 'root'@'localhost' IDENTIFIED BY 'xxx';
恢复后必做三件事:校验、清理、重置 GTID
物理恢复看似快,但最容易漏掉元数据漂移问题。比如从主库拷来数据迁到新从库,不处理 GTID 就会同步错乱;残留的 mysql.general_log 表可能占满磁盘。
上线前检查清单:
- 运行
mysqlcheck -u root -p --all-databases --check,重点看innodb_table_stats和innodb_index_stats是否损坏 - 删掉源库遗留的
slow_query_log_file、general_log_file路径下的日志文件(它们还在往旧路径写) - 如果是 GTID 模式迁移,必须执行
RESET MASTER;+SET GLOBAL gtid_purged = 'xxx';(值来自源库SELECT @@global.gtid_executed;)
物理拷贝快是快,但每个环节都依赖“严丝合缝”的状态对齐。少查一个配置、多留一个 pid 文件、跳过一次 FLUSH PRIVILEGES,都可能让恢复变成救火现场。











