MySQL 服务器的磁盘空间突然告急,通常不会只表现为“剩余容量变少”。写入可能开始报错,事务提交变慢,主从复制中断,甚至连重启都失败。遇到这种情况,最危险的做法是直接进入 /var/lib/mysql 删除看起来很大的文件。Binlog、InnoDB 表空间、临时表空间都由 MySQL 管理,绕过数据库直接删文件,可能把一次容量故障变成数据损坏或无法恢复。
排查时应先回答三个问题:究竟是哪个文件系统被占满,空间被哪一类文件消耗,这些文件应该通过 MySQL、业务程序还是操作系统清理。下面以 MySQL 8.0/8.4 为主,整理一套从止损到预防的处理顺序。

第一步:确认是容量满了,还是 inode 用完了
先看文件系统容量和 inode:
df -h df -i
Use% 接近 100% 说明容量不足;如果容量仍有剩余,但 IUse% 已满,则可能是大量小文件耗尽了 inode。两种情况的清理方向不同。
接着确认 MySQL 实际使用的数据目录:
SHOW VARIABLES LIKE 'datadir';
假设结果是 /var/lib/mysql/,可以在操作系统侧查看一级目录占用,但不要马上删除:
sudo du -xhd1 /var/lib/mysql | sort -h sudo du -xhd1 /var/log | sort -h
还要检查备份目录、临时目录和根分区。常见情况是备份脚本把 SQL 压缩包写回数据库所在磁盘,或者 /tmp、/var/tmp 与 MySQL 数据目录实际位于同一个文件系统。
如果磁盘已经超过 95%,先暂停会持续产生大量写入的导入、归档、报表和备份任务。必要时为日志或备份临时扩容,给后续操作留出空间。此时不要执行大表重建,因为重建过程本身可能需要额外磁盘。
第二步:检查 Binlog 是否持续堆积
Binlog 记录数据库变更,用于复制和按时间点恢复。写入频繁、保留时间过长,或者清理策略没有生效时,它很容易成为主要占用者。
先查看 Binlog 是否启用、当前文件和保留参数:
SHOW VARIABLES LIKE 'log_bin'; SHOW VARIABLES LIKE 'log_bin_basename'; SHOW VARIABLES LIKE 'binlog_expire_logs_seconds'; SHOW BINARY LOGS;
SHOW BINARY LOGS 能列出服务器当前登记的 Binlog 及大小。若文件数量很多,还要结合业务写入量判断:最近突然暴增,可能是批量更新、循环任务或异常重试;长期缓慢增长,则更像保留策略未配置或清理没有执行。
清理前必须确认三件事:
- 从库、订阅任务或增量同步工具已经读取到什么位置。
- 最近一次完整备份是什么时间,是否仍需要这些日志做按时间点恢复。
- 备份程序是否把 Binlog 文件复制到其他位置,复制是否成功。
确认无依赖后,通过 MySQL 清理,不要在文件系统里运行 rm:
PURGE BINARY LOGS BEFORE '2026-09-21 00:00:00';
也可以保留某个文件及其之后的日志:
PURGE BINARY LOGS TO 'binlog.000128';
第二种写法会删除目标文件之前的日志,目标文件本身保留。执行前应再次核对文件名和复制位置。
MySQL 8.0/8.4 可用 binlog_expire_logs_seconds 设置自动过期时间,例如保留 7 天:
[mysqld] binlog_expire_logs_seconds = 604800
保留多久不能只看磁盘大小,还要与完整备份频率、恢复点目标和复制延迟一起决定。配置后应在变更窗口重载或重启,并持续观察实际清理是否符合预期。
第三步:找出增长最快的库和表
当 Binlog 占用正常时,继续查看表数据和索引。下面的查询按估算总大小排序:
SELECT
TABLE_SCHEMA,
TABLE_NAME,
ENGINE,
TABLE_ROWS,
ROUND(DATA_LENGTH / 1024 / 1024, 2) AS data_mb,
ROUND(INDEX_LENGTH / 1024 / 1024, 2) AS index_mb,
ROUND((DATA_LENGTH + INDEX_LENGTH) / 1024 / 1024, 2) AS total_mb,
ROUND(DATA_FREE / 1024 / 1024, 2) AS data_free_mb
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
ORDER BY DATA_LENGTH + INDEX_LENGTH DESC
LIMIT 30;
对 InnoDB 来说,TABLE_ROWS 和部分空间字段可能是估算值,适合用来定位大户,不应当作精确账单。发现某张表突然变大后,继续检查:
- 是否有日志表、任务表、会话表或审计表没有设置保留周期。
- 某个字段是否写入了异常大的文本、JSON 或二进制内容。
- 是否重复创建了用途相近的索引。
- 是否因批量任务、采集异常或重试逻辑产生重复数据。
- 删除历史数据后,表空间只是变成可复用空间,并未立即归还给文件系统。
不要看到 DATA_FREE 较大就立即运行 OPTIMIZE TABLE。对 InnoDB 表,它通常会重建表和索引,执行期间可能占用额外空间,并带来 I/O、锁等待或业务抖动。磁盘已经接近满载时,应先通过扩容、迁移备份、清理安全日志等方式留出操作空间,再在维护窗口评估重建。
大表治理更稳妥的顺序是:先确认增长来源,修复产生异常数据的任务,再按主键或时间范围分批删除,观察复制延迟和磁盘变化,最后决定是否需要重建回收文件系统空间。
第四步:排查磁盘临时表和 ibtmp1
排序、分组、去重、窗口函数以及包含大字段的中间结果,都可能使用内部临时表。内存容不下时,临时数据会落盘。先查看临时表相关状态:
SHOW GLOBAL STATUS LIKE 'Created_tmp%'; SHOW VARIABLES LIKE 'tmpdir';
重点对比 Created_tmp_tables 与 Created_tmp_disk_tables 的增长速度。绝对值来自服务器启动以来的累计结果,单看一次意义有限,最好间隔 5 到 10 分钟采样,或接入监控计算增量。
再从慢查询日志和 Performance Schema 中找出近期执行时间长、扫描行数大、频繁排序或创建磁盘临时表的 SQL。常见诱因包括:
ORDER BY、GROUP BY无法利用合适索引。- 一次查询读取过多行或返回过宽的结果集。
- 中间结果包含
TEXT、BLOB等大字段。 - 报表任务并发过高,多个大查询同时落盘。
- 临时目录与数据库数据目录共用同一块小磁盘。
InnoDB 的全局临时表空间通常会表现为数据目录中的 ibtmp1。它可能在大量磁盘临时表出现时快速增长。不要在 MySQL 运行期间删除或替换该文件。应先停止制造临时数据的查询,确认空间不再增长,再根据业务窗口评估规范重启或调整临时表空间配置。
仅仅调大内存临时表上限也不是通用解法。并发查询会共同消耗内存,参数设置过大可能把磁盘压力转成内存不足。优先优化 SQL、索引和任务并发,再调整参数。
第五步:检查数据库之外的空间消耗
磁盘挂载点相同,并不代表占用一定来自表文件。还应检查以下位置:
- MySQL 错误日志、慢查询日志和通用查询日志。
- 主从复制环境中的 Relay Log。
- 定时备份、逻辑导出和压缩包。
- 应用上传文件、缓存文件和队列积压。
- systemd journal、Web 服务器日志与容器日志。
- 已经被删除但仍被进程占用的文件。
检查“已删除但未释放”的文件:
sudo lsof +L1
如果大文件显示为 (deleted),说明目录项已删除,但进程仍持有文件描述符,空间要等进程关闭文件后才会释放。不要看到结果就直接重启数据库,应先确认对应进程、服务影响和维护窗口。
慢查询日志和通用查询日志也要通过配置和日志轮转管理。通用查询日志在生产环境可能增长很快,只适合短时间诊断。处理完问题后,应恢复原来的日志策略并验证轮转。
磁盘告急时的推荐处理顺序
可以按下面的顺序执行,尽量避免在信息不足时做破坏性操作:
- 用
df -h、df -i确认具体文件系统和 inode 状态。 - 暂停批量导入、报表、备份等高写入任务。
- 确认 MySQL
datadir、tmpdir、日志目录和备份目录是否共用磁盘。 - 用
SHOW BINARY LOGS判断 Binlog 是否异常堆积。 - 确认复制和恢复需求后,使用
PURGE BINARY LOGS清理。 - 从
INFORMATION_SCHEMA.TABLES找出大表,核对业务增长来源。 - 观察磁盘临时表、慢查询和
ibtmp1,停止异常查询。 - 检查系统日志、备份文件、Relay Log 和已删除未释放文件。
- 释放出安全余量后,再安排大表归档、重建或存储迁移。
每完成一步都重新运行 df -h,并查看 MySQL 错误日志。不要一次执行多项清理,否则出了异常很难判断是哪一步造成的。
修复后如何验收和预防
修复不应以“磁盘空出了一点”为结束。至少验证以下项目:
- 数据库可以正常写入,错误日志没有新的磁盘或表空间错误。
- 主从复制、备份和增量同步恢复正常。
- Binlog 数量与保留时间符合恢复策略。
- 大表增长速度回到合理范围,异常任务已经修复。
Created_tmp_disk_tables不再短时间快速增加。- 数据盘保留了足够的应急空间,监控告警能在 70%、80%、90% 等阶段提前触发。
长期预防可以从三方面入手:对 Binlog、备份和各类日志设置明确保留周期;为业务大表建立容量趋势和归档机制;把数据、临时文件、备份放到容量和性能都合适的文件系统。对于增长明显的表,不要等磁盘告警后才处理,按周观察表大小变化通常更容易发现异常任务。
处理 MySQL 磁盘空间问题,不能停在“找到一个大文件删掉”这一步。还要弄清文件由谁管理、清理会影响什么,以及它为什么持续增长。按文件系统、Binlog、大表、临时表、外围日志的顺序逐层排查,通常能在不破坏数据一致性的前提下解决容量故障。
参考资料
- MySQL 8.4 Reference Manual:PURGE BINARY LOGS Statement。
- MySQL 8.4 Reference Manual:binlog_expire_logs_seconds。
- MySQL 8.4 Reference Manual:The INFORMATION_SCHEMA TABLES Table。
- MySQL 8.4 Reference Manual:Internal Temporary Table Use in MySQL。
- MySQL 8.4 Reference Manual:The InnoDB Temporary Tablespace。
- MySQL 8.4 Reference Manual:OPTIMIZE TABLE Statement。
资料核验日期:2026-09-28。




