是,error 28本质是enospc错误,表示磁盘空间或inode耗尽,但故障点不限于根分区,可能位于tmpdir、datadir、binlog目录或/var/tmp等独立挂载分区,需用df -h逐项检查对应路径。

error 28 真的是磁盘写满了,但不一定是根分区
MySQL 报 Got error 28 from storage engine 或 Got error 28 from table handler,本质就是系统返回了 ENOSPC(No space left on device),即“设备上没有剩余空间”。但它不一定发生在 / 分区——MySQL 会把临时文件、日志、排序中间结果分别写到不同路径,而这些路径可能挂载在独立小分区上。
常见误判点:
- 只运行
df -h看整体,却漏掉/tmp、/var/tmp、/run/mysqld或容器里映射的/mysql-tmp - 没查
SHOW VARIABLES LIKE 'tmpdir';,就默认临时文件在/tmp;有些发行版或 Docker 镜像会设为/var/tmp或/run/mysqld - 忽略 binlog/redo log 所在分区:它们可能和数据目录
datadir不在同一个挂载点
快速定位到底哪个路径卡死了
别靠猜,用三步命令链直接定位瓶颈点:
- 查 MySQL 实际使用的临时路径:
mysql -e "SHOW VARIABLES LIKE 'tmpdir';",然后立刻df -h $(mysql -Nse "SELECT @@tmpdir") - 查数据目录所在分区:
mysql -e "SHOW VARIABLES LIKE 'datadir';"→ 接着df -h /var/lib/mysql(路径按实际输出替换) - 查 binlog 目录:
mysql -e "SHOW VARIABLES LIKE 'log_bin_basename';",若为空则 binlog 默认在datadir;否则对 basename 路径执行df -h - 顺手扫一遍系统级临时区:
df -h /tmp /var/tmp /run/mysqld
只要其中任意一个 Use% 到达 100%,就极大概率是它堵住了。注意:某些云主机或容器环境,/tmp 是内存文件系统(tmpfs),满后会导致 error 28 且不报磁盘告警。
清理时别删错、别杀进程、别重启就完事
磁盘满时 MySQL 进程还在运行,很多文件虽被 rm 删除,但句柄仍被占用(lsof | grep deleted 可见),空间不会立即释放。盲目重启反而可能触发 InnoDB 崩溃恢复失败,尤其 innodb_fast_shutdown != 0 时。
- 优先清日志类可删文件:
PURGE BINARY LOGS BEFORE '2026-04-01 00:00:00';(比直接rm mysql-bin.*安全) - 清系统日志:
journalctl --vacuum-size=100M,避免/var/log/journal吃光/var - 清残留临时文件:
find $(mysql -Nse "SELECT @@tmpdir") -type f -name "MY*" -mtime +1 -delete(MY*是 MySQL 临时表命名惯例) - 确认无大文件被进程占用:
lsof +L1查已删除但仍被打开的文件,必要时kill -9 PID
清理后不用重启 MySQL,空间释放即生效;但新连接是否能用更大内存临时表,取决于 tmp_table_size 和 max_heap_table_size 的当前值。
为什么调大 tmp_table_size 还是报 error 28?
因为这两个变量只控制“内存中能建多大的临时表”,一旦查询需要的临时空间超过该值,MySQL 仍会 fallback 到磁盘临时表——这时真正决定成败的是 tmpdir 所在分区的剩余空间,不是内存大小。
-
SET SESSION tmp_table_size = 268435456;和SET SESSION max_heap_table_size = 268435456;必须同时设,且相等,否则以较小者为准 - 这个设置仅对当前连接有效;短连接应用(如 PHP-FPM 默认)每次请求都是新 session,需在 query 前重设,或改配置文件后重启
- 即便设得再大,只要
tmpdir分区只剩 1KB,ORDER BY 大结果集仍会因无法创建磁盘临时文件而报error 28
最易被忽略的一点:tmpdir 在 MySQL 启动后锁定,SET GLOBAL tmpdir = '/new/path' 完全无效。换路径必须停服务、改配置、验证权限、再启动。











