PHPとMySQLにおける「Error while sending QUERY packet」警告の解決方法

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#database-optimization

エラーの概要20MBの高解像度の商品画像をアップロードしたり、5万行のCSVをインポートしたりしている場面を想像してください。突然プロセスが停止し、PHPが次のような警告を出力します。

Warning: Error while sending QUERY packet. PID=1234

このエラーが発生すると、通常、データベースのトランザクションは即座に終了します。多くの場合、これに続いて有名な「MySQL server has gone away」というメッセージが表示されます。本質的には、PHPスクリプトが十分な太さのないパイプに巨大なデータパケットを押し込もうとしたことが原因です。MySQLは自らを保護するために、単に接続を切断します。

根本的な原因この問題の核心は、MySQLまたはMariaDBの設定にある max_allowed_packet という項目にあります。送信されるすべてのSQLステートメントは、単一の「パケット」にラップされます。MySQL 8.0のデフォルトは16MBですが、5.7のような古いバージョンではわずか4MBから始まることがよくあります。

テキスト、エスケープされた文字、バイナリデータを含むクエリ全体がこの制限を超えると、サーバーは処理を拒否します。サーバーはサイズ超過のパケットをメモリのリスクや悪意のある攻撃の可能性があると見なし、門前払いします。その結果、PHPはデータの送信を完了できなかったと報告します。

ステップ別の解決策### 方法1:max_allowed_packet を恒久的に増やすサーバーの再起動後も有効な解決策とするには、サーバー全体の設定ファイルを変更する必要があります。これがこの問題を解決するための標準的な方法です。

  • 設定ファイルの場所を確認します:Linux (Ubuntu/Debian): /etc/mysql/mysql.conf.d/mysqld.cnf- Linux (CentOS/RHEL): /etc/my.cnf- Windows (XAMPP): C:\xampp\mysql\bin\my.ini- sudo権限または管理者権限でファイルを開き、[mysqld] セクションを探します。- max_allowed_packet の行を追加または更新します。大きなファイルを扱う場合は、通常64MBまたは128MBあれば十分です。[mysqld] max_allowed_packet = 64M- 変更を保存し、MySQLサービスを再起動します:```

Linuxの場合

sudo systemctl restart mysql

Windowsの場合

XAMPPコントロールパネルからMySQLを停止して開始します。


### 方法2:SQL経由で制限を変更する(再起動不要)本番環境でトラブルが発生しており、データベースを再起動できない場合は、SQLコマンドを使用してグローバルに制限を変更できます。これには **SUPER** 権限が必要です。
- MySQLコンソールにアクセスします:```
mysql -u root -p
```- 次のコマンドを実行して、制限を64MBに設定します:```
SET GLOBAL max_allowed_packet = 67108864;

ヒント:値はバイト単位で指定する必要があります。1024 * 1024 * 64 = 67,108,864 です。

方法3:PHPでデータを分割(チャンク)するパケットサイズを増やすのは手っ取り早い解決策ですが、データの扱い方自体を変更する方が良い場合も多いです。サーバーのメモリに負荷をかける1つの巨大なクエリを送信する代わりに、処理を小さなバッチに分割します。

この方法は、バックグラウンドジョブや長時間実行されるインポートにおいて、大幅に安定性が向上します。

<?php
$items = [...]; // 10,000個のアイテムを含む巨大な配列
$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);
    
    // 各クエリは約500倍小さくなります
    $db->query($sql);
}

確認方法TablePlusやphpMyAdminなどのデータベースツールで次のクエリを実行し、変更が反映されたか確認します。

SHOW VARIABLES LIKE 'max_allowed_packet';

64Mに設定した場合、結果は 67108864 になるはずです。依然として古い値が表示される場合は、正しい .cnf ファイルを編集したか、設定を上書きしている別の設定ファイルがないか再確認してください。

予防のヒント- クエリの長さを監視する: 開発環境で strlen($query) を使用し、制限にどれくらい近づいているかをログに記録します。- PHPのメモリを調整する: php.inimemory_limit が、想定される最大のデータベースパケットの少なくとも2倍以上であることを確認してください。- BLOBを外部に逃がす: 50MBのPDFを MySQL のカラムに保存するのではなく、ファイルをフォルダやS3バケットに保存し、データベースにはURLのみを保存するようにします。- プリペアドステートメントを使用する: これで制限を回避できるわけではありませんが、生の文字列連結よりもバイナリデータをきれいに処理できます。

Related Error Notes