MySQL 8.0+ 中直接 UPDATE mysql.user 表无效,因权限系统强制通过 SQL 接口(CREATE USER/GRANT/REVOKE)管理,绕过接口写表不触发数据字典更新与插件同步。

直接改 mysql.user 表在 MySQL 8.0+ 中根本不会持久生效——不是权限没设对,而是服务端压根不认这种操作。
为什么 UPDATE mysql.user 看似成功却无效
MySQL 8.0+ 启用 caching_sha2_password 插件后,权限系统强制走 SQL 接口管理。执行 UPDATE mysql.user SET authentication_string = ... 不会报错,但重启或 FLUSH PRIVILEGES 后变更就消失。这不是 bug,是设计行为:权限校验依赖数据字典状态和插件上下文,绕过接口写表等于往缓存外塞脏数据。
- 旧版(5.7)虽能写入,但容易导致认证失败——比如只改了
authentication_string却漏掉plugin字段 -
FLUSH PRIVILEGES对直写系统表的变更完全无感,它只重载权限缓存,不校验数据一致性 - 即使你有 root 权限,也受此限制;这是服务端硬性拦截,非配置可关
真正有效的权限变更必须走 CREATE USER / GRANT / REVOKE
所有权限增删改都必须使用标准 SQL 语句,MySQL 会自动校验逻辑、更新数据字典、同步缓存,并触发插件适配。
- 新建账号:
CREATE USER 'dev_app'@'10.20.%.%' IDENTIFIED BY 'pwd' REQUIRE SSL; - 精确授权:
GRANT SELECT, INSERT ON app_db.orders TO 'dev_app'@'10.20.%.%'; - 回收高危权限:
REVOKE FILE, SUPER, PROCESS ON *.* FROM 'dev_app'@'10.20.%.%'; - 删多余账号比改 root 更可靠:
DROP USER 'root'@'%';(默认存在,必须显式删)
防止开发人员通过系统表写权限的隐蔽路径
只要给业务账号开了 SELECT 或 INSERT 权限访问 mysql 库,他们就能构造语句篡改权限,再 FLUSH PRIVILEGES 生效——这不是漏洞,是权限模型本身允许的行为。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 绝对禁止:
GRANT SELECT ON mysql.user TO 'dev_app'@'%';,哪怕只读也不行 - 禁用
skip-grant-tables:该参数会让所有权限检查失效,调试时也别开 - 查现有风险:
SELECT User,Host,Select_priv FROM mysql.user WHERE Select_priv='Y';,重点看非 DBA 账号 - 生产环境禁用
GRANT ALL PRIVILEGES ON *.*,它隐式带GRANT OPTION和系统库写权
验证权限是否真被锁死
别信 SHOW GRANTS 的输出,要动手试。用目标账号连上去,执行几个关键操作看是否报错:
-
SELECT @@global.max_connections;→ 应报Access denied; you need (at least one of) the SYSTEM_VARIABLES_ADMIN privilege(s) -
UPDATE mysql.user SET password_expired='Y' WHERE User='dev_app';→ 应报ERROR 1290 (HY000): The MySQL server is running with the --skip-grant-tables option so it cannot execute this statement或权限拒绝 -
SHOW GRANTS FOR CURRENT_USER;→ 输出里不能出现SYSTEM_VARIABLES_ADMIN、CONNECTION_ADMIN、SUPER、GRANT OPTION
最容易被忽略的是 host 匹配精度——'dev_app'@'10.20.%' 和 'dev_app'@'10.20.15.8' 是两个账号,权限需分别清理。










