mysql数据目录迁移必须停库后cp -a拷贝而非mv,需修正权限、selinux/apparmor上下文、systemd protectsystem限制及readwritepaths,并确保innodb_file_per_table路径一致性。

新硬盘挂载后,MySQL 数据目录不能直接 mv 迁移
直接 mv 原数据目录到新盘再改配置,大概率启动失败。MySQL 启动时会校验 ibdata1、ib_logfile* 和表空间文件的路径一致性,且系统用户权限、SELinux 上下文、AppArmor 规则往往不随移动生效。
正确做法是停库 → 拷贝(不是移动)→ 修正权限 → 更新配置 → 启动验证。关键点:
-
cp -a保留所有权限、时间戳、符号链接,别用rsync -a后忘了加--delete清理残留(容易误删) - 新路径属主必须是
mysql:mysql,常见错误是拷贝后仍是root:root - CentOS/RHEL 7+ 默认启用 SELinux,新路径需打上
system_u:object_r:mysqld_db_t:s0上下文,命令:chcon -R -t mysqld_db_t /mnt/newdisk/mysql - Ubuntu/Debian 若启用了 AppArmor,需同步更新
/etc/apparmor.d/usr.sbin.mysqld中的路径白名单
my.cnf 里 datadir 改完,mysqld 还报 Permission denied
不是配置写错了,而是 systemd 服务单元对 MySQL 的文件访问做了额外限制。现代发行版(尤其是 CentOS 8+/Ubuntu 20.04+)的 mysqld.service 默认启用了 ProtectHome=true 和 ProtectSystem=full,会阻止服务读写 /mnt 或 /data 等非标准路径。
解决方法只有两个:
- 在
/etc/systemd/system/mysqld.service.d/override.conf中添加:[Service] ProtectHome=false ProtectSystem=false ReadWritePaths=/mnt/newdisk/mysql
,然后运行systemctl daemon-reload && systemctl restart mysqld - 或彻底禁用该限制(不推荐):
systemctl edit mysqld,填入同上内容
注意:ReadWritePaths 必须精确到目录层级,写成 /mnt/newdisk 不够,得是 /mnt/newdisk/mysql;否则仍被拦截。
迁移后发现 InnoDB 表打开失败,报错 “Table doesn’t exist in engine”
这是典型的表空间路径未同步更新导致。MySQL 8.0+ 默认开启 innodb_file_per_table=ON,每张表的 .ibd 文件独立存放,但其元数据(表名、空间ID等)仍记录在共享表空间 ibdata1 和数据字典中。单纯拷贝文件,字典里的路径指针没变。
安全做法只有一种:用 mysqldump 全量导出再导入。但若数据量大,可走物理迁移 + 字典重建:
- 确保原库已完全停止(
systemctl stop mysqld,不是mysqladmin shutdown) - 拷贝前确认
innodb_fast_shutdown=0已设置并生效(避免后台线程未刷脏页) - 拷贝完成后,首次启动加参数
--innodb-force-recovery=1尝试加载,成功后再用mysqld --initialize-insecure初始化新实例并导入 - 更稳妥的是:停库 →
mysqld --datadir=/old/path --skip-grant-tables --skip-networking &→ 连上去执行FLUSH TABLES WITH READ LOCK;→ 再拷贝 → 解锁 → 切配置启动
挂载新硬盘时,/etc/fstab 里漏了 noatime 和 xfs_opts
MySQL 随机小 IO 密集,频繁更新访问时间戳(atime)会显著拖慢性能,尤其 XFS 文件系统。默认挂载不加 noatime,每次查询都会触发磁盘写 atime,实测 QPS 可降 15%+。
XFS 还需显式指定优化选项:
-
noatime:禁用访问时间更新 -
nobarrier(仅限有掉电保护的 RAID 卡或 NVMe):关闭写屏障,提升吞吐 -
logbufs=8,logbsize=256k:增大日志缓冲,减少 sync 频次
完整示例:/dev/sdb1 /mnt/newdisk xfs defaults,noatime,logbufs=8,logbsize=256k 0 0。漏掉 noatime 是线上最常被忽略的性能黑洞。











