需同时配置MySQL服务端与客户端的max_allowed_packet参数并重启生效,且字段类型、SQL长度、驱动限制、连接池缓存等均需匹配,否则仍会报错。

MySQL 报错 Packet too large 怎么调 max_allowed_packet
直接改对了才能让大 INSERT、LOAD DATA 或长 TEXT/BLOB 字段写入成功。不是所有地方改了都生效,顺序和位置错了白配。
- 必须同时改服务端(
mysqld)和客户端(如mysql命令行、Python 的pymysql连接参数),否则连上就断或写一半报错 -
my.cnf里要放在[mysqld]和[client]两个区块下,单独写在[mysql]下只影响命令行客户端,不解决程序连接问题 - 改完必须重启
mysqld,动态设置SET GLOBAL max_allowed_packet = 64*1024*1024仅对当前会话有效,且重启后丢失 - 单位是字节,
64M要写成67108864或64*1024*1024;配置文件里支持64M写法,但某些旧版本 MySQL 不识别,建议统一用数字
PHP + MySQLi 插入 2MB JSON 字段失败,max_allowed_packet 够但还是报错
PHP 层有独立限制,和 MySQL 服务端无关。光调数据库配置没用,PHP 自己就把包截断了。
-
mysqli默认使用mysqlnd驱动,它内部也维护一个max_allowed_packet缓冲区,值取自 PHP 启动时读到的 MySQL 服务端值,但不会自动同步运行时变更 - 如果 MySQL 服务端已设为 128M,但 PHP 启动后才改的,
mysqli仍按旧值缓存,需重启 PHP-FPM 或 Apache - 更稳妥的做法是在连接后显式检查:
mysqli_get_client_info()看驱动类型,再用mysqli_query($conn, "SELECT @@max_allowed_packet")确认实际生效值 - PDO 用户注意:
PDO::MYSQL_ATTR_MAX_BUFFER_SIZE是客户端缓冲上限,设太小会提前截断,但它不影响服务端校验,只是本地预分配;真正卡脖子的还是服务端max_allowed_packet
为什么 TEXT 字段存不下 10MB 数据,明明 max_allowed_packet 设到了 512M
字段类型本身有容量天花板,max_allowed_packet 只管“单次传输包大小”,不管“字段能存多少”。两者必须同时满足。
-
TINYTEXT最大 255 字节,TEXT是 64KB,MEDIUMTEXT是 16MB,LONGTEXT才是 4GB —— 存 10MB 必须用MEDIUMTEXT或更高 - 即使字段类型够大,插入时整条 SQL 语句长度(含引号、转义字符)也不能超
max_allowed_packet;比如 JSON 字符串里有很多双引号,会被转义成\",实际传输字节数比原始数据多 10%–20% - 用
LOAD DATA INFILE绕过 SQL 解析层,可避免语句膨胀问题,但文件路径必须在 MySQL 服务端本地,且需开启secure_file_priv对应目录
Go 的 database/sql 驱动连 MySQL 写大字段总超时,不是 max_allowed_packet 问题
Go 官方驱动默认启用 multiStatements=true 时,会把整个 SQL 按分号切分,对大字段内容里的分号误判为语句结束,导致解析错位和超时。这不是包大小问题,是协议层误解析。
- 连接字符串里显式关闭:
?multiStatements=false(默认就是 false,但有些封装库或中间件会强制开启) - 确认驱动是否用了
mysql(支持maxAllowedPacket参数)而非mysqldb等旧分支;前者可通过parseTime=true&loc=Local等参数控制行为,后者不支持 - 大字段建议用
stmt.Exec+sql.Named参数化,避免拼接 SQL;二进制数据优先走bytes.Reader或io.Reader接口流式写入,减少内存峰值
最常被忽略的是:改完 max_allowed_packet 后没验证是否真正生效。用 SHOW VARIABLES LIKE 'max_allowed_packet' 查的是当前会话值,而客户端可能连的是另一个未重启的实例,或者用了连接池缓存了旧连接参数。










