如何撤销MySQL普通用户对performance_schema的访问权限并限制其查看系统表信息?
- 内容介绍
- 文章标签
- 相关推荐
本文共计722个文字,预计阅读时间需要3分钟。
MySQL 5.7 默认给予 USAGE 权限(即已创建但未授权任何权限的用户)对 performance_schema 的 SELECT 权限,这是历史兼容性设计,并非 bug。因此,无需担心。直接执行 CREATE USER 'u'@'%'; 创建的用户也能执行 SELECT * FROM performance_schema.events_statements_current;。
如何彻底收回 performance_schema 的 SELECT 权限?
必须显式用 REVOKE 剥离,且需注意作用域和生效时机:
- 对单个用户:执行
REVOKE SELECT ON performance_schema.* FROM 'username'@'host'; - 必须在
mysql系统库所在实例上执行(不能跨实例代理) - 执行后需运行
FLUSH PRIVILEGES;(仅当使用 GRANT/REVOKE 修改权限表时才强制需要;但为保险起见建议加上) - 该操作不影响
information_schema——它由 MySQL 服务层硬编码控制,无法通过权限系统禁用普通用户的SELECT
禁止查看所有系统库的更稳妥做法
仅 revoke performance_schema 不够,因为用户仍可访问 information_schema 中的表名、列名甚至部分统计信息(如 TABLES、COLUMNS)。真正隔离需组合策略:
- 启用
show_compatibility_56=OFF(默认值),避免旧版兼容接口泄露额外元数据 - 设置
sql_mode包含RESTRICTED_SESSION(MySQL 8.0.12+),限制非 SUPER 用户执行某些元数据语句(如SHOW PROCESSLIST) - 对高敏环境,考虑用
mysqld --skip-show-database启动参数,使普通用户执行SHOW DATABASES只返回自己有权限的库(但不阻止他们连上后查information_schema.SCHEMATA) - 最彻底的方式:用
CREATE VIEW封装业务查询,让应用只查视图,再配合DEFINER权限控制,把底层系统表完全挡在 SQL 层之外
验证权限是否真的被收回
别只信 SHOW GRANTS FOR 'u'@'%'; 的输出——它可能缓存或显示不全。真实检测要登录目标用户后手动试:
- 执行
SELECT COUNT(*) FROM performance_schema.events_waits_history_long;→ 应报错ERROR 1142 (42000): SELECT command denied to user ... for table 'events_waits_history_long' - 执行
SELECT SCHEMA_NAME FROM information_schema.SCHEMATA;→ 仍会成功(这是设计如此,无法禁用) - 执行
SHOW ENGINE INNODB STATUS;→ 若返回 “Access denied”,说明PROCESS权限也已被剥离(这和 performance_schema 无关,但常被一并清理)
真正难控的是 information_schema 的读取行为——它不走权限检查路径,只要连接成功就能查部分表。想拦住,只能靠网络层过滤或代理层重写 SQL。
本文共计722个文字,预计阅读时间需要3分钟。
MySQL 5.7 默认给予 USAGE 权限(即已创建但未授权任何权限的用户)对 performance_schema 的 SELECT 权限,这是历史兼容性设计,并非 bug。因此,无需担心。直接执行 CREATE USER 'u'@'%'; 创建的用户也能执行 SELECT * FROM performance_schema.events_statements_current;。
如何彻底收回 performance_schema 的 SELECT 权限?
必须显式用 REVOKE 剥离,且需注意作用域和生效时机:
- 对单个用户:执行
REVOKE SELECT ON performance_schema.* FROM 'username'@'host'; - 必须在
mysql系统库所在实例上执行(不能跨实例代理) - 执行后需运行
FLUSH PRIVILEGES;(仅当使用 GRANT/REVOKE 修改权限表时才强制需要;但为保险起见建议加上) - 该操作不影响
information_schema——它由 MySQL 服务层硬编码控制,无法通过权限系统禁用普通用户的SELECT
禁止查看所有系统库的更稳妥做法
仅 revoke performance_schema 不够,因为用户仍可访问 information_schema 中的表名、列名甚至部分统计信息(如 TABLES、COLUMNS)。真正隔离需组合策略:
- 启用
show_compatibility_56=OFF(默认值),避免旧版兼容接口泄露额外元数据 - 设置
sql_mode包含RESTRICTED_SESSION(MySQL 8.0.12+),限制非 SUPER 用户执行某些元数据语句(如SHOW PROCESSLIST) - 对高敏环境,考虑用
mysqld --skip-show-database启动参数,使普通用户执行SHOW DATABASES只返回自己有权限的库(但不阻止他们连上后查information_schema.SCHEMATA) - 最彻底的方式:用
CREATE VIEW封装业务查询,让应用只查视图,再配合DEFINER权限控制,把底层系统表完全挡在 SQL 层之外
验证权限是否真的被收回
别只信 SHOW GRANTS FOR 'u'@'%'; 的输出——它可能缓存或显示不全。真实检测要登录目标用户后手动试:
- 执行
SELECT COUNT(*) FROM performance_schema.events_waits_history_long;→ 应报错ERROR 1142 (42000): SELECT command denied to user ... for table 'events_waits_history_long' - 执行
SELECT SCHEMA_NAME FROM information_schema.SCHEMATA;→ 仍会成功(这是设计如此,无法禁用) - 执行
SHOW ENGINE INNODB STATUS;→ 若返回 “Access denied”,说明PROCESS权限也已被剥离(这和 performance_schema 无关,但常被一并清理)
真正难控的是 information_schema 的读取行为——它不走权限检查路径,只要连接成功就能查部分表。想拦住,只能靠网络层过滤或代理层重写 SQL。

