必须修正auto_increment计数器至max(id)+1,因int unsigned已达上限4294967295导致主键重复;若无空洞则需升级为bigint或切表迁移。

直接结论:不能靠“重试”或“忽略错误”恢复,必须先修正 AUTO_INCREMENT 计数器,且目标值必须严格大于当前 MAX(id)。
为什么 INSERT 突然报 Duplicate entry '4294967295' for key 'PRIMARY'?
这不是数据冲突,而是自增计数器卡死在字段上限。INT UNSIGNED 最大值是 4294967295,InnoDB 检测到已达顶点后,不再递增,下一次插入仍尝试用这个值——必然主键重复。
常见误判:
- 以为是脏数据导致冲突 → 实际是计数器失效
- 执行
INSERT IGNORE后看似成功 → 实则新行被静默丢弃,业务数据丢失 - 查
SHOW CREATE TABLE看到AUTO_INCREMENT=4294967295就以为“还能用一次” → 错,这是最后一次失败的起点
紧急修复:用 ALTER TABLE ... AUTO_INCREMENT = X 拉回可用位置
核心逻辑:让计数器跳过已删除的空洞,指向第一个未被占用的 ID(即 MAX(id) + 1)。前提是表中确实存在 ID 空洞(比如删过大量中间数据)。
操作前必须确认三件事:
- 执行
SELECT MAX(id) FROM your_table;,记下结果(例如 3820000) - 执行
SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table';,确认它卡在 4294967295 - 检查是否有应用层代码硬编码了 INT 范围(如 Java 的
int类型接收 ID),避免拉回后写入时溢出
安全执行:
ALTER TABLE your_table AUTO_INCREMENT = 3820001;
注意:该语句不锁全表(仅需 MDL 写锁),但会阻塞其他 DDL;线上操作建议在低峰期进行。
如果表里没有空洞(MAX(id) 已接近上限),就不能重置
例如 MAX(id) 是 4294967290,空洞只剩 5 个位置——此时重置毫无意义,5 条之后又崩。
真正可行的路径只有两个:
-
升级字段类型:执行
ALTER TABLE your_table MODIFY id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT;。注意:5.7+ 支持在线 DDL(ALGORITHM=INPLACE),但大表仍需数小时;务必提前在从库验证 -
切表迁移:建新表(
your_table_v2,ID 为BIGINT),双写过渡,再切换读写。比直接改字段更可控,适合无法停写的核心表
别碰 TRUNCATE 或清空重置——业务数据不能丢,外键和关联视图也会断裂。
最容易被忽略的点:事务回滚不释放已分配的 ID
哪怕一条 INSERT 在事务中被 ROLLBACK,它申请到的那个 ID 也永久作废。所以耗尽往往发生在高并发+频繁回滚的场景,而非单纯数据量大。
这意味着监控不能只看当前 MAX(id),还得定期跑:
SELECT AUTO_INCREMENT - (SELECT MAX(id) FROM your_table) AS gap_size FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table';
gap_size 持续缩小,就是耗尽预警信号。等它降到个位数,就真没时间了。











