Packets out of order错误本质是客户端与服务端协议解析不一致,非网络乱序:①max_allowed_packet过小致服务端截断响应;②多进程共享同一MySQL连接句柄引发读写冲突;③MySQL Shell 8.x未指定协议导致X/经典协议切换残留;④caching_sha2_password认证插件与旧客户端不兼容。

Packets out of order 不是网络乱序问题,而是 MySQL 客户端与服务端在协议解析层面彻底对不上号——连接已经异常,只是错误消息写得像“包顺序错了”。
max_allowed_packet 太小导致服务端截断响应
MySQL 服务端收到超出 max_allowed_packet 的结果(比如 SELECT 大字段、BLOB、LOAD DATA),会直接截断或丢弃后续 packet,但客户端还在等完整帧。它下一次读到的字节头不是预期的 0x10(即 packet header byte 16),而是某个随机值(如报错里常见的 Expected 1 received 56),于是判定“次序错乱”。
-
show variables like 'max_allowed_packet'查到的值(默认常为 4MB 或 1MB)只是服务端当前生效值,已有连接不会重读该配置 -
set global max_allowed_packet = 64<em>1024</em>1024只影响新连接,重启前老连接仍会出错 - 必须修改配置文件(如
/etc/my.cnf的[mysqld]段),写入max_allowed_packet = 64M,再重启 mysqld 进程
多进程共享同一个 MySQL 连接句柄
PHP + Swoole 场景最典型:父进程创建一个 PDO 或 mysqli 连接,fork 出多个子进程后,所有子进程共用同一 socket fd。TCP 连接不是线程安全的,更不是进程安全的——各子进程读写互相干扰,服务端发来的 packet 被不同进程抢着读,自然出现 Expected 1 received 27 这类跳变。
- 绝对不要在 fork 后复用连接,每个子进程必须自己调用
new PDO()或mysqli_connect() - 若需复用连接资源,必须上连接池(如 Swoole\Coroutine\MySQL、HikariCP、ProxySQL),由池统一管理生命周期和并发访问
- Laravel、ThinkPHP 等框架若集成 Swoole,要确认 DB 配置中
PDO::ATTR_PERSISTENT是 false,且未开启长连接复用
MySQL Shell 默认用 X 协议引发协议切换残留
MySQL Shell 8.0–8.4 版本执行 mysqlsh root@localhost:3306 时,会先尝试 mysqlx 协议;失败后 fallback 到经典协议,但 socket 状态没清干净,服务端日志记下 MY-010914 Got packets out of order,而客户端可能看似连上了、实则握手不稳。
- 错误日志里搜
MY-010914,再结合客户端是否用的是 Shell 8.x,基本可锁定 - 修复方式很简单:显式指定协议,改用
mysqlsh mysql://root@localhost:3306 - MySQL Shell 9.0+ 已修复,但混用旧版 Shell 的生产环境必须加
mysql://前缀
认证插件不兼容让握手阶段就崩溃
MySQL 8.0 默认用 caching_sha2_password,但老版 PHP mysqlnd、Python mysql-connector-python < 8.0.16、某些 ORM 或代理(如 ProxySQL 旧版)只认 mysql_native_password。服务端发认证包时结构不同,客户端无法解析,直接报 Packets out of order 并断连。
- 查用户插件:
SELECT user, host, plugin FROM mysql.user WHERE user = 'your_user' - 临时兼容:
ALTER USER 'your_user'@'%' IDENTIFIED WITH mysql_native_password BY 'password' - 长期方案:升级客户端驱动,或在 MySQL 配置中设
default_authentication_plugin = mysql_native_password(仅限过渡期)
真正棘手的点在于:这些原因可能叠加出现。比如 Swoole 多进程 + 小 max_allowed_packet + caching_sha2_password,错误日志里全是 MY-010914,但根因分布在客户端、中间层、服务端三层。得一层层剥开看——先盯日志里的 Expected 和 received 数值,再查客户端版本、连接方式、服务端配置,最后动刀。


















