mysql权限与表加锁有什么关系_mysql锁与权限管理

1次阅读

权限不足时lock tables会报错,需显式授予lock tables全局权限;flush tables with read lock需reload权限且绕过read_only;行锁本身不校验权限,但执行前提受权限限制。

mysql权限与表加锁有什么关系_mysql锁与权限管理

权限不足时,LOCK TABLES 会直接报错

不是所有用户都能加表锁。mysql 要求执行 LOCK TABLES 必须拥有 LOCK TABLES 权限(属于全局权限),且不能是只读账号(read_only=1 时 super 用户仍可锁,但普通用户会被拒绝)。常见错误:Error 1045 (28000): access denied for user 'app'@'%' to database 'test' —— 实际不是库权限问题,而是缺少 LOCK TABLES 权限。

  • 检查权限:运行 SHOW GRANTS FOR CURRENT_USER;,确认输出中包含 LOCK TABLES
  • 授予权限(需 super 或 grant option):GRANT LOCK TABLES ON *.* TO 'app'@'%'; FLUSH PRIVILEGES;
  • 注意:MySQL 8.0+ 中,LOCK TABLES 权限不再隐含在 selectUPDATE 中,必须显式授予
  • 即使有 LOCK TABLES 权限,若当前连接处于事务中(AUTOCOMMIT=0),执行 LOCK TABLES 会自动触发隐式提交,导致事务中断——这是极易被忽略的副作用

FLUSH TABLES WITH READ LOCK 需要 RELOAD 权限,且绕过 read_only 限制

全局读锁命令 FLUSH TABLES WITH READ LOCK 不同于普通表锁,它要求 RELOAD 权限(而非 LOCK TABLES),并且能强制阻塞所有写入——哪怕你已设 read_only=1,这个命令仍会让 super 用户也无法写,因为它是物理级阻塞。

  • 验证权限:SELECT Reload_priv FROM mysql.user WHERE User='root' AND Host='%'; 返回 Y 才有效
  • 执行后,任何 DML(INSERT/UPDATE/delete)、DDL(CREATE/DROP)都会挂起等待,包括 root 用户
  • 解锁必须用 UNLOCK TABLES,且只能由同一连接执行;断开连接会自动释放锁,但可能导致备份不一致
  • 该命令会阻塞 mysqldump --single-transaction 的一致性快照起点,所以不要在备份脚本里混用

InnoDB 行锁不受用户权限控制,但权限影响能否触发行锁

行锁(如 SELECT ... FOR UPDATE)本身不校验权限——只要语句能执行成功,InnoDB 就加行锁。但“能否执行成功”取决于权限:比如没 SELECT 权限,连查询都失败,自然无法加锁;没 UPDATE 权限,SELECT ... FOR UPDATE 可以执行(因只读),但后续 UPDATE 会报错。

  • 典型陷阱:给应用账号只授 SELECT 权限,却让它执行 SELECT ... FOR UPDATE —— 看似能跑通,但实际锁住了行,而业务逻辑又没后续更新,导致锁长期滞留
  • 行锁是否生效,还依赖索引:若 WHERE 条件未命中索引,InnoDB 会升级为表锁(甚至全表扫描锁),此时又回到权限和锁粒度双重风险
  • 权限越精细,越容易误判锁行为:例如对某列有 SELECT 权限但无 UPDATE 权限,SELECT col1 FROM t WHERE id=1 FOR UPDATE 成功加锁,但 UPDATE t SET col2=1 WHERE id=1 直接报错 ERROR 1142 (42000): UPDATE command denied,锁却没释放

备份/维护场景下,权限与锁的组合最容易出事

线上做逻辑备份、主从切换或数据迁移时,常同时涉及权限变更和锁操作。这时权限配置稍有偏差,就会让锁失效或过度阻塞。

  • 例如用 mysqldump --lock-all-tables:它内部执行 FLUSH TABLES WITH READ LOCK,所以 dump 账号必须有 RELOAD 权限,否则报错退出,但 dump 进程可能已部分写入脏文件
  • 再如用 pt-online-schema-change:它依赖 SELECT/INSERT/UPDATE/DELETETRIGGER 权限,若漏授 TRIGGER,工具会退化为锁表方式,导致业务阻塞
  • 最隐蔽的是权限缓存:修改了 mysql.user 表但忘了 FLUSH PRIVILEGES,新权限不生效,锁命令看似执行成功,实则未真正加锁(尤其在 MySQL 5.7 及更早版本)

权限本身不控制锁的类型或范围,但它决定了你“有没有资格发起锁操作”。真正危险的不是锁不住,而是锁住了却没人意识到——比如一个只有 SELECT 权限的账号执行了 FOR UPDATE,锁持续到事务结束,而 dba 查权限时只看 DML 权限,完全忽略这种“只读但带锁”的中间态。

text=ZqhQzanResources