在生产环境中,有时候你会遇到一些看似简单但实际上很棘手的问题。最近我就碰到了一次典型的服务器磁盘空间告急,最后通过迁移 MySQL 数据目录成功解决了问题。本文记录整个过程,包括我的分析思路、迁移步骤、踩坑和经验总结,希望对你有帮助。
一、问题背景
公司的一台业务数据库服务器,运行的是 MySQL 8.0.20,数据目录默认放在:
/data/mysql-8.0.20/data
随着业务数据的增长,/data
分区的空间渐渐被吃满,监控报警开始提示:
Disk space usage on /data exceeds 98%
打开 df -h
一看,果然 /data
分区只剩不到 1GB,而 /home
分区却很空闲,有几十 MB 可用。
二、分析思路
-
确认空间问题是否由 MySQL 引起
du -sh /data/mysql-8.0.20/data
结果:
38G /data/mysql-8.0.20/data
→ 明确是 MySQL 数据目录占了大头。
-
能否扩容
/data
分区?- 由于这台是虚拟机,业务部门不方便短期扩容。
- 考虑将数据目录迁移至磁盘更大的
/home
分区。
-
迁移 MySQL 数据目录的关键点
- 必须 停库迁移,否则数据会不一致。
- 迁移后需要修改 配置文件 datadir。
- 新路径权限必须正确(
mysql:mysql
,SELinux 要处理)。 - 迁移过程要有 回退方案(先复制,验证成功后再删旧数据)。
三、实现步骤
在正式进行迁移前,我们先看一下整个迁移的流程图,帮助你对后续的步骤有直观印象。
1. 停止 MySQL 服务
sudo systemctl stop mysqld
ps -ef | grep mysqld # 确认进程关闭
2. 创建新目录
sudo mkdir -p /home/mysql/data
3. 迁移数据
建议先复制,确保安全:
sudo cp -av /data/mysql-8.0.20/data/* /home/mysql/data/
(等验证 OK 再删除旧目录)
4. 修改 MySQL 配置
编辑 /etc/my.cnf
(路径可能不同,根据实际环境调整):
[mysqld]
datadir=/home/mysql/data
socket=/home/mysql/data/mysql.sock[client]
socket=/home/mysql/data/mysql.sock
5. 更新权限
sudo chown -R mysql:mysql /home/mysql/data
sudo chmod 750 /home/mysql/data
6. SELinux 处理(重要)
CentOS / RHEL 默认 /home 属于 home_t
类型,MySQL 无法直接访问,需要修改安全上下文:
查看 SELinux 状态:
getenforce
如果输出 Enforcing
,执行:
sudo semanage fcontext -a -t mysqld_db_t "/home/mysql/data(/.*)?"
sudo restorecon -Rv /home/mysql/data
(如果只是验证,可以先用 setenforce 0
暂时关闭 SELinux)
7. 启动 MySQL
sudo systemctl start mysqld
8. 验证新目录生效
SHOW VARIABLES LIKE 'datadir';
结果应为:
/home/mysql/data/
9. 清理旧目录
确认 MySQL 稳定运行几天再删除旧目录:
sudo rm -rf /data/mysql-8.0.20/data
四、踩坑记录
在迁移过程中我踩了一些坑,也分享出来避免大家踩同样的雷:
-
忘记改权限 → 启动失败
The server quit without updating PID file
解决:
chown -R mysql:mysql /home/mysql/data
-
SELinux 拒绝访问新目录
- 关闭 SELinux 后启动成功 → 说明是安全上下文问题
- 永久解决:使用
semanage fcontext
和restorecon
修改为mysqld_db_t
-
客户端连接失败
- 因为 socket 文件路径变了,要同步修改
[client]
部分的socket
配置
- 因为 socket 文件路径变了,要同步修改
五、经验总结
-
生产环境操作一定要有回退方案
- 先
cp
而不是直接mv
- 保留旧数据目录,确认没问题后再删
- 先
-
权限和 SELinux 是 MySQL 无法启动的核心原因
- 迁移路径后务必
chown
+ SELinux 规则调整
- 迁移路径后务必
-
提前规划数据目录的位置
- 尽量放在可扩容的分区,或者挂载点规划时预留足够磁盘空间
-
验证后再清理
- 保留一段时间旧目录,是救命稻草
六、参考命令速查表
# 停mysql
systemctl stop mysqld# 拷贝数据目录
cp -av /data/mysql-8.0.20/data/* /home/mysql/data/# 修改配置文件
vim /etc/my.cnf# 权限
chown -R mysql:mysql /home/mysql/data
chmod 750 /home/mysql/data# SELinux规则调整
semanage fcontext -a -t mysqld_db_t "/home/mysql/data(/.*)?"
restorecon -Rv /home/mysql/data# 启动MySQL
systemctl start mysqld# 验证数据目录
SHOW VARIABLES LIKE 'datadir';
💡 写在最后
这次迁移虽然只是换了个目录,但背后体现的是处理 🛠 生产问题的三个关键能力:
- 快速定位根因
- 制定低风险方案
- 预留回退路径
实际生产中,看似琐碎的小问题,通过“按步骤 + 防风险”去执行,才不会把小问题变成大事故。