LỗiHãy tưởng tượng bạn đang tải lên một hình ảnh sản phẩm độ phân giải cao dung lượng 20MB hoặc nhập một tệp CSV với 50.000 dòng. Đột nhiên, quá trình này dừng lại và PHP đưa ra một cảnh báo:
Warning: Error while sending QUERY packet. PID=1234
Điều này thường làm dừng giao dịch (transaction) cơ sở dữ liệu ngay lập tức. Thường thì theo sau đó là thông báo lỗi nổi tiếng "MySQL server has gone away". Về cơ bản, script PHP của bạn đã cố gắng đẩy một gói dữ liệu khổng lồ qua một đường ống không đủ rộng. Để tự bảo vệ, MySQL chỉ đơn giản là ngắt kết nối.
Nguyên nhân gốc rễVề cốt lõi, vấn đề này nằm ở thiết lập max_allowed_packet trong cấu hình MySQL hoặc MariaDB của bạn. Mỗi câu lệnh SQL bạn gửi đi được gói gọn trong một "packet" (gói tin) duy nhất. Trong khi MySQL 8.0 mặc định là 16MB, các phiên bản cũ hơn như 5.7 thường bắt đầu ở mức chỉ 4MB.
Nếu truy vấn của bạn—bao gồm tất cả văn bản, các ký tự escaped và dữ liệu nhị phân—vượt quá giới hạn này, máy chủ sẽ từ chối xử lý. Nó coi gói dữ liệu quá khổ là một rủi ro tiềm ẩn về bộ nhớ hoặc một cuộc tấn công độc hại và đóng cửa lại. PHP sau đó báo cáo rằng nó không thể hoàn thành việc gửi dữ liệu.
Các bước khắc phục### Cách 1: Tăng max_allowed_packet vĩnh viễnĐể có một giải pháp duy trì sau khi khởi động lại máy chủ, bạn phải sửa đổi tệp cấu hình trên toàn hệ thống. Đây là cách tiêu chuẩn để khắc phục vấn đề này.
- Xác định vị trí tệp cấu hình của bạn:Linux (Ubuntu/Debian):
/etc/mysql/mysql.conf.d/mysqld.cnf- Linux (CentOS/RHEL):/etc/my.cnf- Windows (XAMPP):C:\xampp\mysql\bin\my.ini- Mở tệp với quyền sudo hoặc administrator và tìm phần[mysqld].- Thêm hoặc cập nhật dòngmax_allowed_packet. Nếu bạn đang xử lý các tệp lớn, 64MB hoặc 128MB thường là đủ:[mysqld] max_allowed_packet = 64M- Lưu các thay đổi và khởi động lại dịch vụ MySQL:```
Trên Linux
sudo systemctl restart mysql
Trên Windows
Stop và start MySQL qua XAMPP Control Panel.
### Cách 2: Thay đổi giới hạn qua SQL (Không cần khởi động lại)Nếu bạn đang gặp sự cố trên môi trường production và không thể khởi động lại cơ sở dữ liệu, bạn có thể thay đổi giới hạn trên toàn cầu bằng lệnh SQL. Bạn sẽ cần quyền **SUPER** để thực hiện việc này.
- Truy cập vào console của MySQL:```
mysql -u root -p
```- Chạy lệnh này để đặt giới hạn thành 64MB:```
SET GLOBAL max_allowed_packet = 67108864;
Mẹo nhanh: Giá trị phải tính bằng byte. 1024 * 1024 * 64 = 67,108,864.
Cách 3: Chia nhỏ dữ liệu trong PHPTăng kích thước gói tin là một cách khắc phục nhanh, nhưng tốt hơn hết là thay đổi cách bạn xử lý dữ liệu. Thay vì gửi một truy vấn khổng lồ gây áp lực lên bộ nhớ máy chủ, hãy chia nhỏ công việc thành các đợt (batch) nhỏ hơn.
Cách tiếp cận này ổn định hơn đáng kể đối với các tác vụ chạy ngầm hoặc quá trình nhập dữ liệu kéo dài:
<?php
$items = [...]; // Một mảng khổng lồ gồm 10.000 mục
$batchSize = 500;
$batches = array_chunk($items, $batchSize);
foreach ($batches as $batch) {
$sql = "INSERT INTO logs (message, created_at) VALUES ";
$rows = [];
foreach ($batch as $item) {
$rows[] = "('" . addslashes($item['msg']) . "', NOW())";
}
$sql .= implode(',', $rows);
// Mỗi truy vấn giờ đây nhỏ hơn khoảng 500 lần
$db->query($sql);
}
Xác minhKiểm tra xem các thay đổi của bạn có hiệu lực hay không bằng cách chạy truy vấn này trong bất kỳ công cụ cơ sở dữ liệu nào như TablePlus hoặc phpMyAdmin:
SHOW VARIABLES LIKE 'max_allowed_packet';
Nếu bạn đặt thành 64M, kết quả sẽ là 67108864. Nếu nó vẫn hiển thị giá trị cũ, hãy kiểm tra kỹ xem bạn đã chỉnh sửa đúng tệp .cnf chưa và liệu có tệp cấu hình thứ hai nào đang ghi đè cài đặt của bạn hay không.

