如何用 GRANT 语句限制用户只能访问指定数据库
MySQL 默认不自动限制用户访问范围,必须显式授权。核心是只对目标数据库(如
app_db)授予所需权限,且不使用通配符
*指代所有库。 执行
GRANT SELECT, INSERT ON app_db.* TO 'user1'@'localhost';—— 这样 user1 只能操作
app_db下的表,对
mysql、
information_schema或其他库完全不可见 避免写成
GRANT ... ON *.*,哪怕只是临时测试,否则等于开放全部数据库 授权后必须执行
FLUSH PRIVILEGES;,否则变更不生效(尤其在直接修改
mysql.db表后)
为什么 SHOW DATABASES 仍能看到其他库
这是常见误解:权限控制的是「能否访问」,不是「能否看见」。只要用户有任意数据库权限,
SHOW DATABASES就会列出所有库名(除系统库可能被隐藏),但尝试 USE 其他库会报错
Access denied for database 'xxx'。 想真正隐藏库名,需启用
show_database_privilege(MySQL 8.0.29+),并确保用户没有
SHOW DATABASES权限 更通用的做法是:不授
SHOW DATABASES,改用
SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA配合行级过滤逻辑(应用层控制) 注意
performance_schema和
sys库默认对所有已认证用户可见,无法通过 GRANT 隐藏
撤销权限时容易漏掉的点
用
REVOKE删除权限不等于清空所有访问能力,特别是当用户有多个 GRANT 记录或全局权限残留时。 检查来源:
SELECT * FROM mysql.db WHERE User='user1';,确认是否还有旧的
Db记录未清理
REVOKE不会删除用户账号本身,也不会影响其从
mysql.user表继承的全局权限(如
USAGE),需单独处理 如果之前执行过
GRANT ... ON *.*,必须先
REVOKE ... ON *.*,再重新按库授权,否则旧权限仍生效
MySQL 8.0 的角色(ROLE)方式更适合长期管理
直接给用户授予权限难维护,尤其当多个用户需相同访问策略时。角色机制能解耦权限定义与用户绑定。
创建角色:CREATE ROLE 'app_reader';授权给角色:
GRANT SELECT ON app_db.* TO 'app_reader';把角色赋给用户:
GRANT 'app_reader' TO 'user1'@'localhost';启用角色(会话级):
SET ROLE 'app_reader';,或设为默认:
SET DEFAULT ROLE 'app_reader' TO 'user1'@'localhost';
角色的好处是权限变更只需改一次定义,所有绑定用户自动同步;但要注意 MySQL 8.0.16 以下版本不支持动态默认角色,需显式
SET ROLE。
