MySQL表级SELECT授权必须指定数据库名,如GRANT SELECT ON db.table TO 'u'@'h';用户须预先创建,列权限和DEFINER视图可能绕过限制。

GRANT SELECT ON table_name 语法必须带数据库名
MySQL 的权限系统不支持脱离数据库上下文直接授权给“某张表”,GRANT SELECT ON my_table TO 'user'@'host' 这种写法会报错 ERROR 1144 (42000): Illegal GRANT/REVOKE command; please consult the manual to see which privileges can be used。必须显式指定数据库名,格式为 database_name.table_name。
实操建议:
- 先确认目标表所在的数据库:
SELECT DATABASE();或查information_schema.tables - 授权语句必须写成:
GRANT SELECT ON mydb.users TO 'reporter'@'192.168.1.%'; - 如果数据库名含特殊字符(如短横线、空格),要用反引号包裹:
GRANT SELECT ON `my-db`.`log_table` TO 'reader'@'%'; - 执行后别忘了
FLUSH PRIVILEGES;—— 虽然多数情况下自动生效,但在某些 MySQL 版本或配置下仍需手动刷新
用户不存在时不能直接 GRANT,得先 CREATE USER
MySQL 8.0+ 默认禁止隐式创建用户。如果 'alice'@'localhost' 尚未存在,直接 GRANT SELECT ON sales.orders ... 会报错 ERROR 1410 (42000): You are not allowed to create a user with GRANT。
正确顺序是:
- 先创建用户(指定认证插件更稳妥):
CREATE USER 'alice'@'localhost' IDENTIFIED WITH mysql_native_password BY 'p@ssw0rd'; - 再授权:
GRANT SELECT ON finance.invoices TO 'alice'@'localhost'; - 如只需登录权限不执行任何操作,可跳过 GRANT,但必须有
USAGE权限,否则连接会拒绝
只授 SELECT 权限不等于能访问表里所有字段
MySQL 的列级权限是独立控制的,GRANT SELECT 默认授予整张表所有列。但如果你后续执行了 REVOKE SELECT(col_a) ON db.t FROM 'u'@'h',那么即使有表级 SELECT 权限,查询 col_a 也会被拒绝。
验证当前用户对某表的实际可查字段:
SELECT COLUMN_NAME, IS_NULLABLE, DATA_TYPE
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 'users'
AND COLUMN_NAME IN (
SELECT COLUMN_NAME FROM information_schema.COLUMN_PRIVILEGES
WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 'users'
AND GRANTEE = '''reporter''@''%'''
AND PRIVILEGE_TYPE = 'SELECT'
);注意:这个查询依赖 COLUMN_PRIVILEGES 视图,它仅在显式授过列权限时才返回非空结果;默认未设列权限时,该视图无记录,表示整表可查。
撤销权限后残留的 DEFINER 或 VIEW 依赖可能引发间接访问
如果用户虽无直接 SELECT 权限,但拥有某个 DEFINER = 'root'@'%' 的视图(CREATE VIEW v_users AS SELECT * FROM users),且该视图被设为 SQL SECURITY DEFINER,则用户执行 SELECT * FROM v_users 仍能读取原表数据——权限检查按 DEFINER 身份进行。
排查这类隐蔽通道:
- 查用户创建的视图:
SELECT TABLE_NAME, DEFINER, SECURITY_TYPE FROM information_schema.VIEWS WHERE DEFINER LIKE '%user%'; - 查用户拥有的存储过程/函数:
SELECT ROUTINE_NAME, DEFINER FROM information_schema.ROUTINES WHERE DEFINER LIKE '%user%'; - 真正限制访问,要一并
DROP VIEW或改SQL SECURITY INVOKER,不能只靠撤表权限
权限粒度比想象中更细,表级 SELECT 只是起点;DEFINER、列权限、视图链路这些环节稍不注意,就可能让授权形同虚设。


















