Sửa lỗi MySQL 'Error writing file' (Errcode: 28) – Hết dung lượng đĩa

intermediate🗄️ MySQL2026-04-16| MySQL 5.7 / 8.0, Linux (Ubuntu, Debian, CentOS/RHEL), mọi loại storage backend

Error Message

Error writing file '/tmp/MYxxxxxx' (Errcode: 28 - No space left on device)
#mysql#disk-space#storage

Lỗi gặp phải

Error writing file '/tmp/MYxxxxxx' (Errcode: 28 - No space left on device)

Lỗi này xuất hiện khi một truy vấn cần ghi file tạm — để sắp xếp, GROUP BY, ORDER BY, hoặc JOIN lớn — nhưng phân vùng đích không còn dung lượng. MySQL đặt tên các file tạm này là MYxxxxxx và ghi vào tmpdir, mặc định là /tmp trên Linux. Khi phân vùng đó đạt 100%, mọi truy vấn cần ghi xuống đĩa sẽ thất bại ngay lập tức với Errcode 28. Không có cơ chế thử lại, không có xử lý nhẹ nhàng — chỉ là lỗi tức thì.

Bước 1 – Xác nhận phân vùng đã thực sự đầy

df -h

Kiểm tra xem phân vùng /tmp hoặc / có hiển thị 100% không. Đừng dừng lại ở đó — hãy kiểm tra thêm inode:

df -i

Một phân vùng có thể cạn kiệt inode trước khi hết dung lượng byte. Nếu IUse% hiển thị 100%, cách xử lý vẫn như vậy: xóa file. Dung lượng còn trống không có ý nghĩa gì khi không còn inode để tạo file mới.

Bước 2 – Tìm và dọn sạch rác

Xóa file tạm MySQL cũ còn sót lại từ các truy vấn bị crash

# Stop MySQL first — don't remove active temp files
sudo systemctl stop mysql

# Remove stale temp files
sudo rm -f /tmp/MY*

# Restart
sudo systemctl start mysql

Tìm các file lớn nhất trên phân vùng đầy

sudo du -sh /* 2>/dev/null | sort -rh | head -20

Trên máy chủ bận rộn, lệnh này thường phát hiện binary log của MySQL chiếm 20–50 GB, log ứng dụng chưa bao giờ được xoay vòng, hoặc các bản backup dump cũ mà ai đó quên dọn dẹp.

Xóa binary log cũ (nếu binlog đang bật)

-- See exactly how much space binlogs are using
SHOW BINARY LOGS;

-- Purge logs older than 3 days
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 3 DAY;

Hoặc từ shell:

sudo find /var/lib/mysql -name 'mysql-bin.*' -mtime +3 -delete

Cắt bớt các file log quá lớn

sudo truncate -s 0 /var/log/mysql/error.log
sudo journalctl --vacuum-size=200M

Bước 3 – Chuyển tmpdir sang phân vùng lớn hơn (giải pháp lâu dài)

Các phân vùng /tmp nhỏ — thường chỉ 1–5 GB trên bản cài Linux mặc định — nhanh chóng bị đầy khi MySQL xử lý các tập kết quả lớn. Hãy trỏ tmpdir đến nơi có dung lượng thực sự rộng rãi hơn.

Tạo thư mục tạm riêng biệt

sudo mkdir -p /var/lib/mysql-tmp
sudo chown mysql:mysql /var/lib/mysql-tmp
sudo chmod 750 /var/lib/mysql-tmp

Cập nhật my.cnf / my.ini

[mysqld]
tmpdir = /var/lib/mysql-tmp

Trên Ubuntu/Debian, file config nằm tại /etc/mysql/mysql.conf.d/mysqld.cnf. Trên CentOS/RHEL là /etc/my.cnf.

Khởi động lại MySQL

sudo systemctl restart mysql

Bước 4 – Giảm dung lượng tạm mà truy vấn cần dùng

Không có thêm dung lượng đĩa ngay lúc này? Bạn có thể giảm nhu cầu ghi file tạm của MySQL bằng cách đẩy nhiều công việc hơn vào RAM.

Tăng bộ đệm sắp xếp trong bộ nhớ

[mysqld]
tmp_table_size      = 256M
max_heap_table_size = 256M
sort_buffer_size    = 4M

Đây là các giá trị cấp session, nên bạn có thể điều chỉnh cho một truy vấn nặng duy nhất mà không cần khởi động lại MySQL:

SET SESSION tmp_table_size = 268435456;
SET SESSION sort_buffer_size = 4194304;
-- then run your heavy query

Truy tìm truy vấn gây ra lỗi

SHOW PROCESSLIST;

Tìm các truy vấn có State: Copying to tmp table hoặc Creating sort index — đó là những ứng viên đang tràn xuống đĩa. Chạy EXPLAIN trên chúng. Thiếu index trên cột sắp xếp thường loại bỏ hoàn toàn việc sử dụng file tạm.

Xác nhận đã khắc phục

# 1. Confirm tmpdir is set correctly
SHOW VARIABLES LIKE 'tmpdir';

# 2. Check free space on the new tmpdir partition
df -h /var/lib/mysql-tmp

# 3. Re-run the failing query — it should complete without error

Muốn theo dõi file tạm xuất hiện theo thời gian thực trong khi truy vấn chạy? Lệnh một dòng này sẽ làm được điều đó:

watch -n1 'ls -lh /var/lib/mysql-tmp/'

Ngăn lỗi tái diễn

  • Cảnh báo ở mức 80%, không phải 100% — khi phân vùng đã đầy, các truy vấn đã bắt đầu thất bại rồi. Hãy đặt cảnh báo dung lượng đĩa trên phân vùng tmpdir ở ngưỡng 80% để có thời gian xử lý.
  • Tự động hết hạn binary log — thêm binlog_expire_logs_seconds = 259200 (3 ngày) vào my.cnf. Nếu không có cấu hình này, binlog sẽ tích lũy vô thời hạn và dễ dàng chiếm hơn 20 GB trên máy chủ ghi nhiều.
  • Xoay vòng error log MySQL — cấu hình logrotate cho /var/log/mysql/error.log. Máy chủ bận rộn có thể tạo ra hàng trăm MB log mỗi ngày; nếu không xoay vòng sẽ tích lũy rất nhanh.
  • Sửa truy vấn, không chỉ sửa đĩa — một truy vấn đổ hàng gigabyte vào /tmp thường là do thiếu index. Chạy EXPLAIN, tìm full table scan, và thêm index phù hợp. Cách này giải quyết triệt để nguyên nhân gốc rễ.

Related Error Notes