直接改datadir不生效是因权限机制拦截,需同步调整挂载属性、文件属主、SELinux/AppArmor策略,并确保my.cnf、systemd配置及初始化路径三者一致。

直接改 datadir 配置不生效,是因为 MySQL 启动时被系统级权限机制拦住了——不是配置错了,是磁盘挂载、文件属主、安全模块(SELinux/AppArmor)三者没对齐。
确认挂载点可用且符合 MySQL 要求
云磁盘挂载后必须满足三个硬性条件:可读写、非 noexec/nosuid、路径末尾无斜杠。否则 MySQL 进程连打开目录都失败。
- 运行
mount | grep /data/mysql,确认输出中不含noexec、nosuid、nodev - 检查
df -h /data/mysql,确保实际可用空间足够,别只看挂载大小 - 用
ls -ld /data/mysql看权限,MySQL 服务以mysql用户运行,该目录必须对其可进入(x)、可读(r)
同步数据时别碰 InnoDB 系统文件
从 /var/lib/mysql/ 复制数据到新路径,ibdata1、ib_logfile*、undo_* 这些不能直接复制——它们和初始化时的 datadir 绑定,强行迁移会导致启动时报 InnoDB: Database page corruption on disk 或反复崩溃。
- 停库后用
rsync -avh --progress /var/lib/mysql/ /data/mysql/同步,但同步完立刻删掉新目录下的ibdata1、ib_logfile*、undo_* - 再执行
mysqld --initialize --user=mysql --datadir=/data/mysql(MySQL 8.0+)或mysql_install_db --user=mysql --datadir=/data/mysql(5.7 及以前),重建系统表空间 - 注意:
--initialize会生成新 root 临时密码,务必记下
绕过 SELinux 或 AppArmor 拦截是刚需
Ubuntu 默认用 AppArmor,CentOS/RHEL 默认开 SELinux——它们会拦截 MySQL 访问非标准路径,日志里只显示模糊的 Permission denied,根本不会告诉你被谁拦了。
- Ubuntu 查
/var/log/kern.log,看到apparmor="DENIED" ... name="/data/mysql/"就说明是 AppArmor 拦的;编辑/etc/apparmor.d/usr.sbin.mysqld,在已有规则后加两行:/data/mysql/ r,/data/mysql/** rwk,
然后运行sudo systemctl reload apparmor - CentOS/RHEL 运行
semanage fcontext -a -t mysqld_db_t "/data/mysql(/.*)?"再执行restorecon -Rv /data/mysql - 别用
setenforce 0临时关 SELinux,MySQL 启动时会检测并拒绝运行(报错World-writable config file is insecure)
三个地方的 datadir 必须一致
只改 /etc/my.cnf 里的 datadir 是最常见失误。MySQL 启动时还会校验 socket、pid 文件路径是否与数据目录逻辑自洽,systemd 服务也可能硬编码旧路径。
- 在
[mysqld]段下显式写全:datadir = /data/mysqlsocket = /data/mysql/mysql.sockpid-file = /data/mysql/mysqld.pidlog-error = /data/mysql/error.log - 运行
systemctl cat mysqld,如果看到Environment="MYSQLD_OPTS=--datadir=/var/lib/mysql",必须覆盖它:
执行sudo systemctl edit mysqld,填入:[Service]Environment="MYSQLD_OPTS=--datadir=/data/mysql" - 验证最终生效路径:
mysql -uroot -p -e "SELECT @@datadir;",输出必须是/data/mysql/(末尾带斜杠)
最容易被忽略的是:MySQL 8.0+ 初始化后,mysql.ibd 和 sys 库的元数据也绑定新路径,此时若用旧备份还原整个 mysql 目录,会引发权限校验失败。真要还原,得用 mysqldump 导出再导入,而不是文件级拷贝。


















