Khắc phục cảnh báo 'Error while sending QUERY packet' trong PHP & MySQL

intermediate🐘 PHP2026-06-10| PHP 7.4/8.x, MySQL 5.7/8.0+, MariaDB, Linux (Ubuntu/CentOS), Windows (XAMPP/WAMP)

Error Message

Warning: Error while sending QUERY packet. PID=1234
#php#mysql#mariadb#toi-uu-hoa-co-so-du-lieu

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òng max_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.

Mẹo phòng ngừa- Theo dõi độ dài truy vấn: Sử dụng strlen($query) trong môi trường phát triển để ghi lại mức độ bạn đang tiến gần đến giới hạn.- Điều chỉnh bộ nhớ PHP: Đảm bảo memory_limit trong php.ini lớn hơn ít nhất 2 lần so với gói dữ liệu cơ sở dữ liệu lớn nhất dự kiến.- Lưu trữ BLOB bên ngoài: Thay vì lưu trữ các tệp PDF 50MB trong một cột MySQL, hãy lưu các tệp vào một thư mục hoặc S3 bucket và chỉ lưu URL trong cơ sở dữ liệu.- Sử dụng Prepared Statements: Chúng sẽ không bỏ qua giới hạn, nhưng chúng xử lý dữ liệu nhị phân sạch sẽ hơn so với việc nối chuỗi thô.

Related Error Notes