朕喜技术(ZhenxiJS)
2026.09.03
1 分钟阅读

系统盘坏了 MySQL 5.7 数据如何完整恢复:把坏盘当数据盘物理迁移 datadir(宝塔 Debian11 实测)

关键词:MySQL 5.7 数据恢复、系统盘损坏、坏盘数据盘迁移、datadir 物理迁移、宝塔 MySQL、server_uuid 冲突 auto.cnf、ibdata1、视图触发器存储过程丢失、Debian 11、InnoDB 崩溃恢复

一、问题背景

一台 Debian 11 + 宝塔面板 v13.0.0 + MySQL 5.7 的服务器只有一块系统盘,上面跑着多个站点的业务库(商城/博客/用户中心/ERP)。某天系统盘"系统层面"坏了,机器起不来(开机崩溃/引导丢失)。但硬盘本身大概率还能读到,MySQL 的数据文件仍在盘上。

把坏盘拆下当普通数据盘挂到一台全新机器(已装好 Debian11+宝塔+MySQL5.7),问题来了:旧盘里 MySQL 5.7 的数据(含存储过程、触发器、视图、每个库表)怎么完整导到新机器,一行都不能丢?

关键限制:旧系统已无法引导,旧 MySQL 起不来,用不了 mysqldump 逻辑导出。这正是"系统盘坏了、把旧盘当数据盘抢救 MySQL"的经典场景。

二、复现步骤

无 docker CLI 时可在 pipeline 容器内直接复现(本环境实测)。用同版本数据库引擎建两套 datadir:

# 1) 初始化"旧盘" datadir 并写入 4 个业务库+中文数据+视图/触发器/存储过程
mariadb-install-db --user=mysql --datadir=/srv/oldmysql --auth-root-authentication-method=normal
mariadbd --defaults-file=/tmp/my-old.cnf &     # 启动旧库
mysql -uroot < populate.sql                     # 写入业务数据
mysql -uroot -e "SHOW DATABASES;"
# cms_blog  erp_report  legacy_shop  usercenter

# 2) 模拟系统盘坏了:停掉旧 MySQL,数据仍完整留在 /srv/oldmysql
mysqladmin -uroot shutdown

# 3) 初始化"新机器"全新 datadir(无业务数据),启动一次确认空库
mariadb-install-db --user=mysql --datadir=/srv/newmysql ...
mysql -uroot -e "SHOW DATABASES;"              # 只有系统库,无任何旧业务库

三、根本原因

  • MySQL 的全部用户数据 + 结构对象(视图/触发器/存储过程)都以文件形式物理存放在 datadir(宝塔默认 /www/server/data,含 ibdata1、ib_logfile*、mysql/、各业务库目录)。
  • 系统盘坏的是"操作系统引导/根文件系统层",只要底层块设备可读、datadir 文件未损坏,整套数据就完整存在。
  • 新旧两台 MySQL 大版本一致(5.7),frm/ibd/ibdata1 等数据文件格式兼容、可直接复用。
  • 因此最稳妥的恢复路径是 文件级物理迁移(datadir 整体替换),天然保留所有对象与数据;这往往优于"非要先把旧 MySQL 跑起来再用 mysqldump 导"。

四、解决办法

物理迁移 datadir 关键 6 步:

  1. 停掉旧 MySQL(模拟系统盘坏了,数据留在旧卷/旧目录)。
  2. 停掉新机 MySQL,准备替换它的 datadir。
  3. 整体拷贝旧 datadir 到新 datadir:先清空新 datadir(避免新机初始化的 ibdata1/mysql 混进来),再 cp -a /src/. /data/(含隐藏文件、保留权限与符号链接)。
  4. 修复属主 chown -R mysql:mysql <datadir>(mysql:5.7 镜像内 uid=999;本机/宝塔以实际 MySQL 运行 uid 为准)。
  5. 删掉 datadir 里的 auto.cnf:旧 auto.cnf 记录旧 server_uuid,与新机冲突会导致 MySQL 拒绝启动;删除后让 MySQL 重启时自动重新生成 uuid。
  6. 重启新机 MySQL,再用校验脚本核对 4 库行数、中文抽样、视图/触发器/存储过程是否齐全。
# docker 卷版(项目前缀用 docker compose config --volumes 查)
docker run --rm -v <proj>_new_mysql_data:/data alpine sh -c 'find /data -mindepth 1 -delete || true'
docker run --rm -v <proj>_old_mysql_data:/src:ro -v <proj>_new_mysql_data:/data alpine sh -c 'cp -a /src/. /data/'
docker run --rm -v <proj>_new_mysql_data:/data alpine chown -R 999:999 /data
docker run --rm -v <proj>_new_mysql_data:/data alpine rm -f /data/auto.cnf
docker compose up -d new-mysql

五、验证

物理迁移后启动新库并核对,零丢失:

  • 恢复出全部 4 个业务库:cms_blog erp_report legacy_shop usercenter;
  • 各表行数与旧库一致(orders/products/posts/users/sales_report 均完好);
  • 中文/特殊字符无乱码:迪迦、张三、华东、含 <>/'" 与 emoji 🌍 的内容完整;
  • 结构对象齐全:视图 v_active_products、触发器 trg_orders_after_insert、存储过程 sp_order_count_by_status 均在;
  • 迁移后服务可重启、root 可登录;向表插数据时触发器能正常执行(自动写审计表),证明迁移后的结构对象真正可用。

六、经验与避坑

  1. 系统盘坏了 ≠ 数据没了:只要数据盘可读、datadir 完整,物理迁移即可整库恢复,不必纠结旧系统能否引导。
  2. 同版本才可直接搬 datadir:两台都是 MySQL 5.7(数据文件格式兼容)才能整体替换;跨大版本(如 5.7→8.0)通常仍需逻辑导出/升级流程,不能直接搬。
  3. datadir 属主必须对:chown -R mysql:mysql 缺失会报 Fatal error: Can't open and lock privilege tables。mysql:5.7 镜像是 uid 999,宝塔/本机可能不同,以实际为准。
  4. server_uuid 冲突要删 auto.cnf:直接搬入旧 datadir 若不删 auto.cnf,MySQL 会因 server_uuid 重复/无效拒绝启动。
  5. 别混两套数据:替换前务必清空新 datadir,防止把新机自带的 ibdata1/mysql 目录和旧数据搅在一起。
  6. 拷贝用整目录:cp -a /src/. /data/ 保留隐藏文件与权限;不要只 cp *.frm *.ibd 漏文件。
  7. 非正常关机数据目录:MySQL 启动会自动重放 redo log(ib_logfile*)做崩溃恢复,一般无需人工干预;仅当报 InnoDB ... appears to be corrupted 才谨慎用 innodb_force_recovery。
  8. 先备份再动:动手前可对旧 datadir 先做只读/冷备一份,宁稳勿急。

七、可复现命令

cd scenario/2026-09-03-1400
docker compose up -d --build
# 按 README「推荐恢复路径」执行物理迁移后:
docker compose exec app bash
mysql -h new-mysql -uroot -pNewRoot@2026 < /workspace/scenario/2026-09-03-1400/verify.sql

版权声明

本文为博主原创文章,遵循 CC BY-NC-SA 4.0 许可协议。 转载请注明出处:http://localhost/blogs/2026-09-03-1400-mysqldatadir

分享这篇文章