本质是MySQL将临时数据写入空间有限的/tmp或ibtmp1而非预期路径,需先定位tmpdir与innodb_tmpdir实际落盘位置,再针对性释放ibtmp1或迁移tmpdir至大分区,严禁删除ibdata1等核心文件。

临时文件写入过多导致磁盘空间不足,本质是 MySQL 在执行排序、分组、大事务或 binlog 重放时,把本该落盘的临时数据塞进了空间有限的 /tmp 或 ibtmp1,而不是你预期的 /var/lib/mysql。直接删文件或硬重启可能丢数据,得先定位写入点、再针对性释放。
查清 tmpdir 和 innodb_tmpdir 写在哪
MySQL 临时文件不只往一个地方写。tmpdir 控制 SQL 层临时表(如 CREATE TEMPORARY TABLE、ORDER BY 落盘)、innodb_tmpdir 控制 InnoDB 引擎层临时表空间(如大事务中的内部排序),两者默认都可能是 /tmp——而 CentOS 默认把 /tmp 挂成内存盘(tmpfs),大小受限于 RAM,极易撑爆。
- 执行
SELECT @@tmpdir, @@innodb_tmpdir;确认实际路径 - 运行
df -h /tmp /var/lib/mysql对比各分区使用率,85% 以上就是瓶颈 - 如果
@@tmpdir是/tmp且df -h /tmp显示已用 100%,问题就在这儿,不是数据目录满
立刻释放 ibtmp1 但别碰 ibdata1
ibtmp1 是 InnoDB 全局临时表空间,大事务、JSON 处理、复杂 GROUP BY 都会把它撑到几十 GB;但它和 ibdata1 不同:前者可安全重建,后者删了实例就起不来。
- 先确认无长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60;,结果为空才能继续 - MySQL 8.0.13+ 可在线收缩:
ALTER TABLESPACE innodb_temp_tablespaces DISCARD; - 更通用的做法是重启 mysqld —— 重启后
ibtmp1自动重建为初始大小(通常 12MB),前提是innodb_temp_data_file_path没设固定大小 - 绝对不要
rm -f ibdata1或ib_logfile*,这些是共享表空间和重做日志核心文件,删完实例无法启动
把 tmpdir 指向真实大分区
改配置比清理更治本。临时文件写进内存盘 /tmp 是设计缺陷,不是容量问题。
- 新建目录并授权:
sudo mkdir -p /data/tmp && sudo chown mysql:mysql /data/tmp && sudo chmod 755 /data/tmp - 在
/etc/my.cnf的[mysqld]段加一行:tmpdir = /data/tmp - 重启生效:
sudo systemctl restart mysql - 验证是否生效:
SELECT @@tmpdir;应返回/data/tmp,且df -h /data确保该分区有足够余量(建议预留 ≥30%)
别忽略 tmpfs 和 inode 这两个隐形杀手
报 No space left on device 不一定是磁盘块耗尽,也可能是 tmpfs 内存上限或 inode 耗光。
- 查 tmpfs 实际大小:
df -h /tmp如果显示 Size 和 Avail 接近(比如都是 16G),说明它挂的是内存盘,扩容只能换路径,不能调大小 - 查 inode 是否耗尽:
df -i /tmp,如果 Use% 达 100%,说明小文件极多(如日志碎片、短生命周期临时文件),sudo rm -f /tmp/*可立即释放 - 检查是否有“幽灵文件”:
lsof +L1,输出里带DEL标记的文件已被删除但进程仍占用,需 kill 对应进程才能真正释放空间
临时文件爆满往往发生在备份、恢复、从库同步或大事务提交瞬间,这时候最危险的操作是盲目 rm -rf /tmp/* 或重启——若恰有未提交事务,可能触发不可逆回滚。优先改 tmpdir 路径,再清理 ibtmp1,最后才动 /tmp 本身。路径一换,后续所有临时操作自动避开瓶颈,这才是可持续的解法。


















