近期在客户执行 MySQL 用户创建及授权操作时,数据库实例发生异常。经排查确认,原因为 MySQL 权限表损坏,导致权限变更操作触发实例异常。
考虑到数据库规模约 80GB,为保证恢复效率与稳定性,采用业务数据逻辑导出、新建数据库并重建用户权限后再导入数据的方式完成恢复。数据库运行正常业务恢复。
问题现象:
MySQL数据库在做创建用户并授权,执行FLUSH PRIVILEGES时,数据库CRASH, 后面反复重启未能启动。

Note: 从函数调用中有看到是用户访问权限表。
关键函数调用链:
acl_init()– 权限表初始化acl_reload()– 权限表重新加载reload_priv_idx()– 权限索引重新加载populate_roles_caches()– 角色缓存填充find_acl_user()– 查找ACL用户
MySQL权限表架构解析
MySQL权限系统采用多级缓存机制:
- 内存缓存: 权限信息加载到内存中
- 磁盘存储: mysql数据库中的权限表
- 缓存同步: 通过
FLUSH PRIVILEGES同步
// 简化的权限加载流程
acl_init()
→ acl_reload()
→ reload_priv_idx()
→ populate_roles_caches()
可能的原因分类:
| 类别 | 具体可能性 | 优先级 |
|---|---|---|
| 数据文件问题 | 1. 权限表(mysql.user)损坏或格式不兼容 2. 数据文件物理损坏 | 高 |
| 软件配置问题 | 1. MySQL二进制文件或DLL损坏 2. 配置文件错误 3. 版本兼容性问题 | 中 |
| 系统环境问题 | 1. 内存硬件故障 2. Windows权限不足 3. 文件系统权限问题 | 中 |
| 操作问题 | 1. 不当的权限表操作 2. 未授权的数据修改 | 低 |
RENAME USER或create user, FLUSH PRIVILEGES 操作需要重新加载权限表, 重新加载过程中访问了无效或已释放的内存地址.
解决方法:
方案一:安全模式启动修复(推荐)
适用场景: 权限表轻微损坏,需要保留现有数据
# 1. 停止MySQL服务
net stop MySQL80
# 2. 以跳过权限检查模式启动
C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld --console --skip-grant-tables
# 3. 连接MySQL(无需密码)
mysql -u root
# 4. 修复权限表
FLUSH PRIVILEGES;
# 5. 重启正常服务
方案二:权限表替换
mysql> select * from mysql.tables_priv;
mysql> show create table mysql.tables_priv\G
*************************** 1. row ***************************
Table: tables_priv
Create Table: CREATE TABLE `tables_priv` (
`Host` char(255) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT '',
`Db` char(64) COLLATE utf8mb3_bin NOT NULL DEFAULT '',
`User` char(32) COLLATE utf8mb3_bin NOT NULL DEFAULT '',
`Table_name` char(64) COLLATE utf8mb3_bin NOT NULL DEFAULT '',
`Grantor` varchar(288) COLLATE utf8mb3_bin NOT NULL DEFAULT '',
`Timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`Table_priv` set('Select','Insert','Update','Delete','Create','Drop','Grant','References','Index','Alter','Create View','Show view','Trigger') CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '',
`Column_priv` set('Select','Insert','Update','References') CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '',
PRIMARY KEY (`Host`,`User`,`Db`,`Table_name`),
KEY `Grantor` (`Grantor`)
) /*!50100 TABLESPACE `mysql` */ ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0 ROW_FORMAT=DYNAMIC COMMENT='Table privileges'
1 row in set (0.00 sec)
根据DDL 创建新表tables_priv_new
INSERT INTO tables_priv_new SELECT * FROM tables_priv;
FLUSH TABLES tables_priv,tables_priv_new;
RENAME TABLE
tables_priv TO tables_priv_old
,tables_priv_new TO tables_priv;
FLUSH PRIVILEGES;
方案三:检查和修复数据文件
适用场景: 怀疑数据文件损坏
# 1. 停止MySQL服务
net stop MySQL80
# 2. 备份重要数据目录
xcopy "C:\ProgramData\MySQL\MySQL Server 8.0\Data\mysql" "D:\Backup\mysql_backup" /E /H /K
# 3. 运行数据检查和修复
mysqlcheck -u root -p --all-databases --auto-repair
# 4. 重点关注权限表检查
mysqlcheck -u root -p mysql user db tables_priv columns_priv procs_priv --auto-repair
方案四:重新初始化数据目录(激进方案)
适用场景: 严重损坏,其他方案无效
# ⚠️ 警告:此操作会删除所有数据,必须提前备份!
# 1. 停止MySQL服务
net stop MySQL80
# 2. 备份整个数据目录
xcopy "C:\ProgramData\MySQL\MySQL Server 8.0\Data" "D:\Backup\mysql_full_backup" /E /H /K
# 3. 删除原数据目录内容
rmdir /S /Q "C:\ProgramData\MySQL\MySQL Server 8.0\Data"
# 4. 重新初始化
mysqld --initialize-insecure --console
# 5. 重启服务
net start MySQL80
# 6. 从备份中恢复业务数据
处理过程
安全模式启动
C:\Program Files\MySQL\MySQL Server 8.0\bin>mysqld --console --skip-grant-tables
2026-02-04T11:37:42.026345Z 0 [System] [MY-010116] [Server] C:\Program Files\MySQL\MySQL Server 8.0\bin\mysqld.exe (mysqld 8.0.13) starting as process 2464
2026-02-04T11:37:44.487253Z 0 [System] [MY-010232] [Server] Crash recovery finished.
2026-02-04T11:37:45.726577Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
结果: 数据库可以启动,但在执行 FLUSH PRIVILEGES 时再次崩溃。
由于权限表严重损坏,库也不大,采用导入导出
逻辑导出所有业务数据:
# 安全模式启动参数
mysqld --console --skip-grant-tables --shared-memory
# 数据导出(排除系统库)
mysqldump -u root -p --all-databases --ignore-table=mysql.user --ignore-table=mysql.db > data_backup.sql
重新初始化MySQL实例:
# 停止服务
net stop MySQL80
# 备份后删除数据目录
# 重新初始化
mysqld --initialize-insecure --console
# 重启服务
net start MySQL80
逻辑导入业务数据:
mysql -u root -p < all_databases_backup.sql
— over —