reload权限必须用on .全局授予,不可库表级拆分;lock tables则可按库授权,两者常组合用于备份但作用域与风险不同。

必须用 ON *.* 授予 RELOAD,LOCK TABLES 则可按库授权;两者常一起配给备份账号,但作用域和风险完全不同。
RELOAD 权限只能全局授予(ON *.*)
MySQL 把所有 FLUSH 类操作(FLUSH LOGS、FLUSH TABLES WITH READ LOCK、FLUSH PRIVILEGES 等)统一收口在 RELOAD 权限下,不支持库级或表级拆分。
- 写成
GRANT RELOAD ON app_db.* TO 'bkp'@'192.168.1.%'会静默失败——语句不报错,但权限实际没写入 - 正确写法只有:
GRANT RELOAD ON *.* TO 'bkp'@'192.168.1.%' - MySQL 8.0+ 要求用户已存在,不能在
GRANT中隐式创建;若用户不存在,先执行CREATE USER 'bkp'@'192.168.1.%' IDENTIFIED BY 'xxx' - 验证是否生效:运行
SHOW GRANTS FOR 'bkp'@'192.168.1.%',输出中必须明确出现RELOAD ON *.*
LOCK TABLES 权限可以按库精确控制
LOCK TABLES 是库级权限,允许用户对指定数据库内的表加锁(如 LOCK TABLES t1 READ),它不涉及全局状态,所以能限制作用范围。
- 最小化授权示例:
GRANT LOCK TABLES ON app_db.* TO 'bkp'@'192.168.1.%' - 若需跨多个库备份,逐个授权:
GRANT LOCK TABLES ON billing_db.* TO 'bkp'@'192.168.1.%'、GRANT LOCK TABLES ON user_db.* TO 'bkp'@'192.168.1.%' - 别写
ON *.*——那等于开放对所有库的锁能力,可能被误用于阻塞关键业务表 -
LOCK TABLES不提供读写能力,SELECT 权限仍需单独授予,例如:GRANT SELECT ON app_db.* TO 'bkp'@'192.168.1.%'
为什么 mysqldump 还报 Access denied?常见漏项
即使 RELOAD 和 LOCK TABLES 都给了,mysqldump 在某些参数组合下仍会失败,原因往往不是权限本身,而是组合缺失或匹配偏差。
- 主机名不一致:
'bkp'@'localhost'和'bkp'@'127.0.0.1'是两个独立账号,远程连接时实际登录 host 是'bkp'@'192.168.1.100',但你只授了'bkp'@'192.168.1.%'?确认SELECT USER(), CURRENT_USER()输出 - 漏了
SELECT:RELOAD和LOCK TABLES都不包含读取数据的能力,没SELECT就连mysqldump --no-lock都跑不起来 - 用了
--single-transaction但库中有 MyISAM 表:此时mysqldump会自动降级为FLUSH TABLES WITH READ LOCK,仍依赖RELOAD+LOCK TABLES - MySQL 8.0+ 密码插件不兼容:检查
SHOW CREATE USER 'bkp'@'192.168.1.%',若认证插件是caching_sha2_password且客户端不支持,连接直接失败,看起来像权限问题
真正容易被忽略的是权限生效边界
RELOAD 的危险性不在“刷缓存”这个动作本身,而在于它和 LOCK TABLES 组合后,能让一个账号在任意时刻对任意库执行全局锁——哪怕你只打算让它备份一个库。生产环境里,最常出问题的不是权限没给够,而是给了之后没人记得它还能触发 FLUSH TABLES WITH READ LOCK,导致主库突发性写入阻塞。务必把账号绑定到具体 CIDR 段,禁用 '%',并确保该账号密码不与其他系统共享。











