MySQL 8.0.16+升级后磁盘爆满主因是ibtmp1膨胀,非tmpdir写满;根本原因是TEMPTABLE引擎启用后受temptable_max_ram限制(默认物理内存3%),超限直接写入ibtmp1,且该参数不支持动态修改,必须在配置文件中设置,并同步调整max_heap_table_size和internal_tmp_mem_storage_engine。

MySQL 8.0.16+ 升级后磁盘爆满,大概率不是 tmpdir 写满了,而是 ibtmp1 在撑爆根分区——这个文件不走 /tmp,也不能用 lsof +D /tmp 查到。
为什么改了 tmp_table_size 还没用?
MySQL 8.0 已彻底移除 tmp_table_size 参数。如果你从 5.7 升级上来,配置文件里还留着它,mysqld 启动时会静默忽略,不报错也不警告。运行 SELECT @@tmp_table_size 会返回 0 或直接报错 Unknown system variable 'tmp_table_size'。
真正起作用的是这两个参数:
-
max_heap_table_size:控制 MEMORY 表和内存临时表上限,也约束 TEMPTABLE 引擎的内存使用 -
internal_tmp_mem_storage_engine:MySQL 8.0 默认为TempTable(比 MEMORY 更省内存、支持 BLOB),不建议改回MEMORY
必须在配置文件中显式设置两者,例如:
[mysqld] max_heap_table_size = 268435456 internal_tmp_mem_storage_engine = TempTable
temptable_max_ram 必须配,且不能动态改
这是 MySQL 8.0.16+ 新增的核心参数,决定 TEMPTABLE 引擎总内存池上限。默认值是物理内存的 3%(上限 4 GiB),对报表类查询极易卡死。它不支持 SET GLOBAL,必须写进配置文件。
实操步骤:
- 先查当前值:
SELECT @@temptable_max_ram;(单位字节,比如2147483648= 2 GiB) - 在
/etc/my.cnf的[mysqld]段添加:temptable_max_ram = 4G(注意:MySQL 8.0.23+ 才完全支持G单位,旧版本建议写4294967296) - 若物理内存 ≥ 128 GiB,可设为
6G,但别超物理内存 15%,否则可能触发系统 OOM - 重启前务必执行:
SET GLOBAL innodb_fast_shutdown = 0;,再SHUTDOWN;,确保旧ibtmp1可被安全重建
怎么确认真是临时表在撑爆磁盘?
别一看到 The table is full 或根分区 100% 就改配置。先验证根源:
- 查 MySQL 实际用的临时目录:
SELECT @@tmpdir;,然后df -h看对应挂载点是否真满了 - 查状态变量:
SHOW GLOBAL STATUS LIKE 'Created_tmp_disk_tables';和Created_tmp_tables,比值超过 15% 就说明大量查询被迫落盘 - 用
lsof +D /path/to/tmpdir(替换为上一步查到的真实路径)排除非 MySQL 进程干扰 - 如果
Created_tmp_disk_tables飙升但/tmp目录没大文件,基本可以断定数据全进了ibtmp1
错误日志里报 The table '/tmp/#sql-xxx' is full 是误导性路径,真实落盘位置是 ibtmp1 ——它位于 datadir 下,不随 tmpdir 变。
ibtmp1 已涨到上百 GB 怎么办?
ibtmp1 是 InnoDB 内部临时表空间,无法在线收缩。它不会因为删临时表、杀线程、刷脏页就变小。
唯一可靠释放方式是重启 MySQL。5.7+ 启动时会自动重建 ibtmp1 回初始 12MB。
如果实在不能重启,可临时加限制防止继续膨胀:
innodb_temp_data_file_path = ibtmp1:12M:autoextend:max:10G
切勿手动 rm -f ibtmp1 —— mysqld 启动时找不到文件会直接失败。
复杂点在于:调参只是兜底,不是万能药。频繁触发说明 SQL 本身有硬伤——比如 GROUP BY JSON_EXTRACT(col, '$.field')、ORDER BY UPPER(name)、或 SELECT 中含 TEXT 字段,这些都会绕过所有内存参数,强制落盘。


















