如何给 MySQL 用户授予指定表的 SELECT 权限
直接用
GRANT SELECT ON database_name.table_name TO 'user'@'host'即可,不需要先创建用户(如果用户已存在)。注意
database_name不能是通配符
*,必须写具体库名;
table_name可以是具体表名,也可以用反引号包裹含特殊字符的表名。
常见错误是漏掉数据库名,比如只写
GRANT SELECT ON table_name TO ...,MySQL 会报错
ERROR 1144 (42000): Illegal GRANT/REVOKE command。权限粒度最小到表级,不支持“某个库下除某几张表外全部授权”这种排除式语法。 执行后必须跟
FLUSH PRIVILEGES(仅当直接操作
mysql系统表时才强制需要;用
GRANT命令通常自动生效) 如果用户从任意主机连接,
'user'@'%'中的
%不匹配 localhost,需额外授权
'user'@'localhost'权限是叠加的:用户已有库级 SELECT 权限,再授表级权限不会冲突,但撤销库级权限不影响已授的表级权限
撤销某张表的权限但保留其他表访问权
MySQL 不支持“撤销某张表而保留同库其他表”的原子操作,
REVOKE必须明确指定和
GRANT完全一致的对象范围。例如之前用
GRANT SELECT ON mydb.orders TO 'u1'@'%'授了权限,那么撤销就得写
REVOKE SELECT ON mydb.orders FROM 'u1'@'%'。
容易踩的坑是误用
REVOKE SELECT ON mydb.* FROM ...——这会把整个库所有表的 SELECT 权限都撤掉,包括你本想保留的那些。 没有“批量排除某几张表”的语法,要保留 9 张表、只撤 1 张,就得先
REVOKE全部,再对那 9 张重新
GRANT
SHOW GRANTS FOR 'u1'@'%'是验证当前权限的唯一可靠方式,别依赖记忆或旧文档 权限变更在当前连接中立即生效,但已打开的事务不受影响
为什么对 INFORMATION_SCHEMA 表授权总是失败
MySQL 禁止对
INFORMATION_SCHEMA显式授权,任何类似
GRANT SELECT ON INFORMATION_SCHEMA.TABLES TO ...的语句都会报错
ERROR 1044 (42000): Access denied for user ... to database 'INFORMATION_SCHEMA'。
这不是权限没给够,而是设计限制:该库只读且元数据访问由全局
SELECT权限或更细粒度的
SHOW DATABASES/
PROCESS等特权间接控制。普通用户默认能查自己有权限的库下的表信息,但看不到其他库结构。 如果用户连
SHOW TABLES都被拒绝,先确认是否至少有对应库的
USAGE权限(新建用户默认有) 想让应用能自动发现表结构,与其绕过限制,不如在业务库中建视图或提供元数据表
performance_schema和
sys同样不可直接授权,逻辑一致
使用列级权限时要注意什么
MySQL 支持列级权限(如
GRANT SELECT(col1, col2) ON db.t1 TO 'u'@'%'),但实际使用率极低,因为 ORM、连接池、查询构建器往往生成
SELECT *或动态字段列表,一旦碰到未授权列就会报错
ERROR 1142 (42000): SELECT command denied to user ... for column 'col3'。
列权限是独立于表权限的,即使用户已有整表
SELECT,再单独授某几列权限也不会覆盖或冲突;但只要查询中涉及任一未授权列,整个语句就失败。 无法用列权限实现“隐藏敏感字段”,因为
SELECT *仍会触发拒绝;必须确保所有 SQL 显式列出已授权列 备份工具(如
mysqldump)默认用
SELECT *,列权限会导致备份失败 权限检查发生在执行阶段,不是解析阶段,所以函数、子查询中引用未授权列同样报错
权限系统本身不复杂,难的是和真实业务查询模式对齐。比如一个 Web 应用用了 Doctrine ORM,默认生成的 SQL 很可能包含未预设授权的列或临时表,上线前务必用目标用户账号连上去跑一遍完整业务流。
