/tmp分区满导致MySQL写临时文件失败,错误码28;需查df -h /tmp、清理#sql-*残留文件,并配置tmpdir、tmp_table_size等参数避免复发。

这不是MySQL配置错了,是/tmp分区真满了——先别进MySQL,直接切系统层查df。
为什么Writing to net或Copying to tmp table其实是磁盘写不进去
这两个状态看着像网络慢或查询卡,实际是MySQL在往tmpdir落盘时被操作系统拒绝(错误码 Errcode: 28)。常见于大排序、GROUP BY、CREATE TABLE AS SELECT等操作。临时文件名通常是#sql-*或ibtmp1,生成后不自动清理,尤其当/tmp是tmpfs(内存挂载)时,几GB就爆满。
-
SELECT @@tmpdir, @@innodb_tmpdir查真实路径,多数指向/tmp,但df -h /tmp可能显示100%,而df -h /还剩20%——别被假象骗 - 如果
/tmp是tmpfs,df -h显示的大小受限于RAM,不是磁盘空间;df -i反而更关键(小文件多易耗尽inode) - 错误日志里若出现
No space left on device或Could not write to tmpdir,就和undo log、事务回滚段完全无关
紧急清理#sql-*残留临时文件
这些文件是MySQL崩溃、查询中断或KILL线程后遗留的,不删掉,磁盘就一直被占着。MySQL重启也不会自动回收。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 先确认归属:
sudo find /tmp -user mysql -name "#sql*" -mmin +5 -ls(只列5分钟前创建的) - 安全删除:
sudo find /tmp -user mysql -name "#sql*" -mmin +5 -delete - 若
find报“Permission denied”,加2>/dev/null过滤;若仍删不掉,说明文件正被mysqld进程占用,用lsof -p $(pgrep mysqld) | grep /tmp确认后kill -9对应线程 - 删完立刻
df -h /tmp验证——有时文件被进程持有,lsof | grep deleted能看到“deleted”标记的大文件,空间并未释放
改tmpdir并限制缓冲区,否则下次照爆
临时清理只是救火。根本解法是让MySQL少往磁盘写临时文件,而不是拼命扩容tmpdir。
- 查当前路径:
SELECT @@tmpdir;如果指向/tmp且该分区小,改配置如tmpdir = /data/tmp(确保MySQL用户有读写权限),然后重启 -
tmp_table_size和max_heap_table_size必须设成完全相等(如都为268435456即256M),二者取小值决定内存临时表上限 - 总和别超物理内存10%,否则可能挤占
innodb_buffer_pool_size,引发更隐蔽的性能抖动 - MySQL 8.0.16+ 还要额外配
temptable_max_ram(不支持运行时修改),否则tmp_table_size会被静默忽略
真正难处理的不是删文件,而是那些被进程持有却已deleted的#sql-*文件——它们看不见、删不掉、空间不释放,得靠lsof揪出来再杀进程。这个细节90%的人第一次遇到时都会卡住。










