创建只读账号需显式授予各库select权限并单独授权information_schema,连接后必须执行set session max_execution_time=30000,且须通过实际sql验证权限与超时是否生效。

创建只读账号并限制查询超时
MySQL 本身不支持直接给账号设置全局 max_execution_time,但可以通过组合方式实现“报表账号只读 + 单条查询强制超时”。核心思路是:用 CREATE USER 创建账号、GRANT SELECT 限定权限、再通过 SET SESSION MAX_EXECUTION_TIME 在连接层控制单语句耗时。
只读权限必须显式授予,不能依赖角色或省略库名
常见错误是执行 GRANT SELECT ON *.* 后发现仍无法查某些视图或系统表——因为 MySQL 的只读不是靠“禁止写”来定义的,而是靠“没给写权限”。必须逐库授权(尤其报表常跨多库),且注意:INFORMATION_SCHEMA 和 performance_schema 默认不开放 SELECT,需单独加。
GRANT SELECT ON \`report_db\`.* TO 'rpt_reader'@'%';GRANT SELECT ON \`dim_db\`.* TO 'rpt_reader'@'%';-
GRANT SELECT ON INFORMATION_SCHEMA.TABLES TO 'rpt_reader'@'%';(如需元数据) - 切勿用
GRANT USAGE或留空权限,那等于没授权
超时必须在每次连接后主动设置,不能靠全局变量
max_execution_time 是会话级变量,SET GLOBAL 对已存在的连接无效,且新连接默认为 0(不限时)。所以必须让报表系统在建连后立即执行 SET SESSION MAX_EXECUTION_TIME = 30000(单位毫秒)。如果用连接池(如 HikariCP、Druid),需配置 connection-init-sql:
SET SESSION MAX_EXECUTION_TIME = 30000
注意:该设置对 SELECT ... FOR UPDATE 无效(但只读账号本就不该有这类语句),且低于 1000 毫秒可能被服务器忽略(取决于 min_examined_row_limit 配置)。
验证账号是否真受限,别只看 GRANT 语句
授权完必须手动验证,否则上线后才发现权限不足或超时未生效。验证步骤:
- 用新账号登录:
mysql -u rpt_reader -p -h xxx - 执行
SELECT @@max_execution_time;确认返回30000 - 执行一个慢查询测试:
SELECT SLEEP(35);应报错Query execution was interrupted, maximum statement execution time exceeded - 尝试写操作:
INSERT INTO t VALUES (1);应报错ERROR 1142 (42000): INSERT command denied to user
真正容易被忽略的是:应用连接池可能复用旧连接(没触发 init-sql),或者中间件(如 MyCat、ShardingSphere)透传了超时设置但没生效——得在实际业务 SQL 上测,不能只测 SLEEP()。











