如何撤销MySQL普通用户对performance_schema的访问权限并限制其查看系统表信息?

2026-04-30 11:072阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计722个文字,预计阅读时间需要3分钟。

如何撤销MySQL普通用户对performance_schema的访问权限并限制其查看系统表信息?

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 中的表名、列名甚至部分统计信息(如 TABLESCOLUMNS)。真正隔离需组合策略:

  • 启用 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。

标签:Mysql

本文共计722个文字,预计阅读时间需要3分钟。

如何撤销MySQL普通用户对performance_schema的访问权限并限制其查看系统表信息?

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 中的表名、列名甚至部分统计信息(如 TABLESCOLUMNS)。真正隔离需组合策略:

  • 启用 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。

标签:Mysql