
GRANT 语句写完没生效?先检查 FLUSH PRIVILEGES
MySQL 的权限变更不会自动刷新,GRANT 执行成功只是把权限记录写入系统表(如 mysql.db),但当前连接和新连接要读取缓存中的权限数据。不手动刷新,新权限对已存在连接无效,新连接也可能延迟生效。
- 执行
GRANT后,必须跟一句FLUSH PRIVILEGES(除非你用的是 MySQL 8.0+ 且只操作mysql.user等少数表,但保险起见仍建议刷) - 如果用户已登录,ta 的当前会话权限不会变——得重新连接才能应用新权限
-
FLUSH PRIVILEGES是轻量操作,不影响运行中的查询,但别在高并发写入时频繁调用
授库级权限时,ON db_name.* 和 ON *.* 差在哪
权限范围错位是权限失控的最常见原因。MySQL 权限分层级:GLOBAL(服务器级)、DB(数据库级)、TABLE(表级)等,ON 后面的语法直接决定作用域。
-
GRANT SELECT ON mydb.* TO 'u1'@'localhost':只允许查mydb库下所有表,不能跨库,也不能查information_schema -
GRANT SELECT ON *.* TO 'u1'@'localhost':全局 SELECT 权限——能查所有库(包括系统库),生产环境几乎从不这么用 - 注意:数据库名里有特殊字符(如短横线)必须用反引号包裹,比如
GRANT ALL ON `my-db`.* TO ... - MySQL 8.0+ 引入角色(
ROLE),推荐用CREATE ROLE+GRANT ... TO role_name管理权限组,避免直接给用户授全局权限
“Access denied for user” 却明明刚 GRANT 过?看三处硬编码细节
这个报错不一定是权限没给,更可能是认证上下文不匹配。MySQL 判断“你是谁”,靠的是 'user'@'host' 这个完整标识符,三个地方极易写错:
- 主机名必须完全一致:
'app'@'10.0.1.%'≠'app'@'10.0.1.5',哪怕后者在前者网段内;'app'@'%'允许任意 host,但不匹配localhost(MySQL 会优先走unix_socket认证,绕过 TCP 层) - 用户名区分大小写(Linux 下),
'App'@'%'和'app'@'%'是两个用户 - 如果用的是 MySQL 8.0+ 默认的
caching_sha2_password插件,而客户端不支持(比如老版本 PHP mysqlnd),即使密码对、权限对,也会报 Access denied——改认证插件或升级驱动
只给 INSERT 但用户还能删数据?小心 GRANT OPTION 和权限继承
权限不是孤立的。一个看似安全的 INSERT 授权,可能因其他配置被放大成高危能力。
-
GRANT INSERT ON mydb.t1 TO 'u1'@'%'本身安全,但如果之前给过GRANT INSERT, DELETE ON mydb.* TO 'u1'@'%',再单独 revokeDELETE时漏写了ON mydb.*,只写了REVOKE DELETE ON mydb.t1,那库级 DELETE 依然有效 -
WITH GRANT OPTION是开关型风险:一旦加上,该用户就能把同级权限转授给别人,相当于有了“子管理员”能力,线上库严禁使用 - MySQL 不支持“只允许 INSERT 某几列”,
INSERT权限默认覆盖整张表;真要列级控制,得用视图(CREATE VIEW)+ 给视图授权,或升级到 MySQL 8.0+ 的列权限(GRANT INSERT(col1,col2) ON ...)
权限系统没有“撤销全部再重授”的快捷方式,每次修改都要确认作用域、主机名、认证插件、是否带 GRANT OPTION——少一个点,就可能埋下越权或锁死的坑。










