先确认当前datadir和生效配置文件:执行show global variables like 'datadir'及mysqld --verbose --help | grep -a 1 "default options",再停服务、rsync全量复制数据,同步更新my.cnf中datadir、socket、pid-file,适配selinux/apparmor策略,并检查systemd服务文件是否硬编码旧路径。

确认当前 datadir 和生效的 my.cnf 路径
别急着改配置,先查清楚 MySQL 实际读的是哪个 datadir、加载的是哪份配置文件。登录 MySQL 执行:SHOW GLOBAL VARIABLES LIKE 'datadir';
再查配置加载顺序:mysqld --verbose --help | grep -A 1 "Default options"
Linux 常见路径是 /etc/my.cnf 或 /etc/mysql/my.cnf;如果多个配置共存(比如 Docker 容器内挂载了额外配置),datadir 可能被后加载的文件覆盖。
停服务 + 完整复制数据(不是 mv,不是部分拷贝)
必须彻底停止 MySQL 进程,否则 ibdata1 和系统表可能处于不一致状态:sudo systemctl stop mysql
确认无残留:ps aux | grep mysqld
然后用 rsync 完整复制(保留权限、符号链接、时间戳):sudo rsync -av /var/lib/mysql/ /new/path/to/mysql/data/
注意末尾的 / —— 漏掉会导致多嵌套一层目录。复制完成后检查新路径下是否存在:ibdata1、mysql/、performance_schema/、sys/
同步更新 datadir、socket、pid-file 和 systemd 配置
只改 datadir 会启动失败,MySQL 8.0 默认还依赖 socket 和 pid-file 路径与数据目录逻辑一致:
在 [mysqld] 段中同时设置:datadir = /new/path/to/mysql/datasocket = /new/path/to/mysql/data/mysql.sockpid-file = /new/path/to/mysql/data/mysqld.pid
若使用 systemd(主流发行版默认),还需检查 /usr/lib/systemd/system/mysqld.service 中是否硬编码了旧路径(如 ExecStart=... 行含 /var/lib/mysql),如有则注释或删掉,让其完全依赖 my.cnf 配置。
处理 SELinux 或 AppArmor 权限拦截
即使 chown -R mysql:mysql /new/path 且 chmod 750 全部到位,服务仍卡在启动阶段、日志只报 Permission denied,大概率是内核级安全模块拦住了:
CentOS/RHEL(SELinux):sudo semanage fcontext -a -t mysqld_db_t "/new/path(/.*)?"sudo restorecon -Rv /new/path
Ubuntu(AppArmor):
编辑 /etc/apparmor.d/usr.sbin.mysqld,在 /var/lib/mysql/** rwk, 下追加一行:/new/path/** rwk,
然后执行:sudo systemctl reload apparmor
这一步跳过,80% 的迁移会在启动时静默失败。
最易被忽略的点:socket 文件路径变更后,客户端连接会因找不到 mysql.sock 报错;若你没改客户端配置(如 [client] 段中的 socket),又不想改应用代码,可加软链:sudo ln -sf /new/path/to/mysql/data/mysql.sock /var/lib/mysql/mysql.sock,但前提是该路径本身已被 SELinux/AppArmor 允许——否则链过去也打不开。











