修改 mysql datadir 必须先停服务,再拷贝原目录并同步修改 my.cnf 中 datadir、socket、pid-file 及 innodb 日志路径,调整新路径权限与 selinux/apparmor 策略,否则启动失败。

修改 datadir 前必须停掉 MySQL 服务
直接改配置再重启,大概率启动失败。MySQL 启动时会校验 datadir 下的文件结构(如 ibdata1、mysql/ 系统库、ib_logfile*),路径一变就找不到元数据或权限不对。正确顺序是:先关服务 → 拷贝整个原 datadir 目录 → 修改配置 → 调整新路径权限 → 再启服务。
常见错误现象:Can't start server: Bind on TCP/IP port. Got error: 98: Address already in use(其实是卡在初始化阶段,日志里真正报错是 InnoDB: The innodb_system data file 'ibdata1' must be writable 或 mysqld: Can't find file: './mysql/plugin.frm')。
- Linux 下用
systemctl stop mysqld或service mysql stop,别只 kill 进程 - 拷贝用
rsync -avP /var/lib/mysql/ /new/path/mysql/(注意末尾斜杠),保留权限和软链 - 新路径属主必须是
mysql:mysql,否则启动被拒:chown -R mysql:mysql /new/path/mysql
my.cnf 里只改 datadir 不够,还要同步改 socket 和 pid-file
很多教程只提 datadir,但 MySQL 启动时依赖这三个路径协同工作。如果只改 datadir,socket 还在 /var/run/mysqld/mysqld.sock,客户端连不上;pid-file 写到旧路径,服务管理脚本会误判进程状态。
在 [mysqld] 段落里必须同时设置:
[mysqld] datadir = /new/path/mysql socket = /new/path/mysql/mysql.sock pid-file = /new/path/mysql/mysqld.pid
注意:socket 路径要和客户端默认值一致,否则 mysql -u root 会报 Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' —— 此时要么加 -S /new/path/mysql/mysql.sock,要么统一改配置。
InnoDB 表空间路径不随 datadir 自动迁移
如果用了独立表空间(innodb_file_per_table=ON,默认),每个 .ibd 文件确实在 datadir 下,拷过去就行。但若关闭了该选项,所有表数据都塞进共享表空间 ibdata1,它也在 datadir 里,同样需一并迁移。
真正容易漏的是 innodb_log_group_home_dir(redo log 路径)和 innodb_undo_directory(undo log 路径)。它们默认和 datadir 同目录,但一旦显式配置过,就必须手动同步改到新路径,否则启动报错:InnoDB: Error: log file ./ib_logfile0 is of different size。
- 检查是否自定义过:执行
mysql -e "SHOW VARIABLES LIKE 'innodb_log_group_home_dir';" - 若返回非空值,需在
my.cnf中显式设为新路径:innodb_log_group_home_dir = /new/path/mysql -
innodb_undo_directory同理,尤其在启用innodb_undo_log_truncate时更关键
SELinux 或 AppArmor 会拦截新路径访问
CentOS/RHEL 默认开 SELinux,Ubuntu/Debian 可能启 AppArmor。即使权限、路径全对,服务仍起不来,日志里出现 Permission denied 且无具体文件名,八成是这个原因。
临时验证:运行 setenforce 0(SELinux)或 sudo systemctl stop apparmor,再试启动。若成功,说明策略限制了访问。
- SELinux 下给新路径打标:
semanage fcontext -a -t mysqld_db_t "/new/path/mysql(/.*)?",再restorecon -Rv /new/path/mysql - AppArmor 需编辑
/etc/apparmor.d/usr.sbin.mysqld,添加类似/new/path/mysql/** rwk,行,然后sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld
这类安全模块的报错不写进 MySQL error log,得查 dmesg 或 /var/log/audit/audit.log 才能看到真实拒绝记录。










