PDO异常:SQLSTATE[HY000] [2006] MySQL服务器已断开连接,位于/var/www/app/src/Database/Connection.php:42
PDOException: SQLSTATE[HY000] [2006] MySQL server has gone away in /var/www/app/src/Database/Connection.php:42
ID: php/pdo-mysql-server-has-gone-away
版本兼容性
| 版本 | 状态 | 引入 | 弃用 | 备注 |
|---|---|---|---|---|
| PHP 7.4 | active | — | — | — |
| PHP 8.1 | active | — | — | — |
| PHP 8.2 | active | — | — | — |
| MySQL 5.7 | active | — | — | — |
| MySQL 8.0 | active | — | — | — |
根因分析
MySQL服务器因超时(wait_timeout或interactive_timeout)、数据包大小超过max_allowed_packet或服务器崩溃/重启而关闭连接,且PHP PDO连接未重新建立。
English
The MySQL server closed the connection due to a timeout (wait_timeout or interactive_timeout), a packet size exceeding max_allowed_packet, or a server crash/restart, and the PHP PDO connection was not re-established.
官方文档
https://dev.mysql.com/doc/refman/8.0/en/gone-away.html解决方案
-
Increase MySQL's wait_timeout and interactive_timeout in my.cnf, e.g., set wait_timeout=28800; interactive_timeout=28800. Then restart MySQL.
-
Increase max_allowed_packet in my.cnf to handle large queries, e.g., set max_allowed_packet=64M. Restart MySQL.
-
Implement connection retry logic in PHP: catch the exception and reconnect using a new PDO instance. Example: try { $stmt = $pdo->query('SELECT 1'); } catch (\PDOException $e) { if ($e->getCode() == 2006) { $pdo = new PDO($dsn, $user, $pass); $stmt = $pdo->query('SELECT 1'); } }
无效尝试
常见但无效的做法:
-
70% 失败
The error is caused by MySQL's timeout, not PHP's execution time; changing PHP settings does not prevent the server from closing idle connections.
-
50% 失败
Persistent connections can mask the issue but may lead to stale connections being reused, causing the same error later; they also consume server resources.
-
80% 失败
Restarting temporarily reopens connections, but the underlying timeout or packet size issue remains, causing the error to recur.