grant 命令的基本语法和权限粒度
MySQL 的
GRANT不是“一键授权”,它严格区分权限层级:全局(
*)、数据库(
db_name.*)、表(
db_name.table_name)、列(
(col1,col2))甚至存储过程。用错层级会导致权限不生效或过度开放。
最常用的是数据库级授权,例如给用户
'appuser'@'192.168.1.%'对
myapp_db的全部操作权限:
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp_db.* TO 'appuser'@'192.168.1.%';必须显式指定主机名(不能只写
'appuser'),否则默认为
'appuser'@'localhost',远程连不上 权限列表不支持通配符如
CRUD,必须写全或用
ALL PRIVILEGES(慎用) 执行后需运行
FLUSH PRIVILEGES;才能立即生效(仅在直接改系统表后才必需;正常
GRANT会自动刷新)
常见错误:Access denied 但账号明明存在
典型现象是创建了用户、执行了
GRANT,应用仍报
Access denied for user 'xxx'@'yyy'。根本原因往往是主机名匹配失败: 客户端连接时用的是 IP,但
GRANT给的是
'user'@'%.example.com'→ DNS 解析失败或反向解析未配置,MySQL 按 IP 匹配,找不到对应账户 用户从本地连却授权给了
'user'@'127.0.0.1',而 MySQL 把
localhost视为 socket 连接,走的是
'user'@'localhost'这条记录(二者权限独立)
GRANT后忘了
IDENTIFIED BY设置密码,或密码策略不兼容(如 MySQL 8.0 默认用
caching_sha2_password插件,旧客户端不支持)
MySQL 8.0+ 的角色(ROLE)替代重复授权
频繁给多个用户授相同权限(如所有运维人员都要有
SELECT权限),硬写
GRANT易出错且难维护。MySQL 8.0 引入角色机制,可先建角色再批量赋予:
CREATE ROLE 'readonly_role';<br>GRANT SELECT ON *.* TO 'readonly_role';<br>GRANT 'readonly_role' TO 'dev1'@'%', 'dev2'@'%';<br>SET DEFAULT ROLE 'readonly_role' TO 'dev1'@'%';角色本身不带密码,也不可直接登录,纯粹是权限容器 用户被赋予角色后,需执行
SET ROLE或设为默认角色才真正启用权限 回收权限只需
DROP ROLE或
REVOKE ... FROM role_name,比逐个用户操作安全
最小权限原则下的实用授权组合
生产环境绝不该用
GRANT ALL PRIVILEGES。以下是几个真实场景的推荐组合: Web 应用后端(PHP/Java):
GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE ON app_db.* TO 'webapp'@'10.0.2.%';—— 禁用
DROP、
CREATE、
ALTER,防止误删表或注入建库 备份账号(mysqldump):
GRANT SELECT, LOCK TABLES, RELOAD ON *.* TO 'backup'@'10.0.1.5';——
RELOAD是为了
FLUSH LOGS,
LOCK TABLES保证一致性,不需要写权限 监控账号(Prometheus exporter):
GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'monitor'@'10.0.3.%';—— 只读状态信息,禁用任何数据访问权限
权限缩放不是靠直觉,得看具体命令需要什么权限。比如
SHOW CREATE VIEW需要
SHOW VIEW权限,而不仅是
SELECT;调用函数需要
EXECUTE,哪怕函数内部只做
SELECT。
