mysql 8.0自增主键重启不丢值,因其将计数器当前值写入redo log并崩溃恢复时重放;而5.7仅存于内存,重启后依赖扫描b+树取max(id)+1重建,手动设置的高值全部丢失。

AUTO_INCREMENT 值重启不丢,不是“更稳了”,而是 8.0 彻底改了存储方式:它把计数器当前值写进 redo log,启动时重放日志恢复——5.7 完全不落盘,重启只能靠扫描 B+ 树取 MAX(id)+1,旧值一概清零。
MySQL 5.7 自增计数器为什么重启就丢
5.7 的 AUTO_INCREMENT 计数器纯内存维护,连数据字典都不写。哪怕你执行 ALTER TABLE t AUTO_INCREMENT = 9999,这个 9999 只存在 InnoDB 内存结构里,不会写入任何持久化介质。
- 重启后,InnoDB 扫描聚簇索引最右叶子节点,取
MAX(id)+ 步长作为新起点,完全无视你设过的高值 - 主从场景下,从库重启后
AUTO_INCREMENT落后主库,INSERT ... SELECT或REPLACE极易触发主键冲突 -
SHOW CREATE TABLE显示的AUTO_INCREMENT=xxx是内存快照,不可信;information_schema.TABLES.AUTO_INCREMENT更是统计缓存,延迟严重
MySQL 8.0 怎么做到重启不丢值
8.0 把自增计数器当作元数据变更处理,每次成功分配(含 INSERT 或显式 ALTER)都记一条 MLOG_TABLE_DYNAMIC_META 类型的 redo 日志。
- 首次建表时
AUTO_INCREMENT = 1就写 redo;5.7 此时还不写 -
INSERT INTO t VALUES()分配 ID 后立刻落 redo;5.7 要等事务提交才隐式更新内存,且不落盘 - 即使表空,只要执行过
ALTER TABLE t AUTO_INCREMENT = 500,8.0 就会落盘;5.7 重启即失效 - 崩溃恢复时,InnoDB 重放 redo 得到最新已分配值,再与表中
MAX(id)比较,取较大者 + 步长——宁可跳,绝不退
容易被忽略的边界情况
持久化不是万能的,这几个点实际运维中常踩坑:
-
mysqldump --skip-auto-increment导出时跳过自增值,还原后AUTO_INCREMENT从 1 开始,和原库不一致 - 升级前是 5.7 表,若当时刚执行过
ALTER TABLE t AUTO_INCREMENT = 1,8.0 启动后真会从 1 开始,哪怕当前MAX(id)是 10000,直接导致主键冲突 -
SHOW CREATE TABLE显示值可信,但information_schema.TABLES.AUTO_INCREMENT不实时刷新,别拿它做判断依据 - 唯一键冲突(
Duplicate entry)时,ID 已分配并写入 redo,回滚不回收——这是性能取舍,不是 bug
MAX(id) 当作下个 ID 来用。这些地方没对齐,8.0 的持久化反而会放大问题。











