MySQL中创建指定数据库只读用户需手动建户并授予SELECT权限,限定IP和库名(用反引号),禁用FILE等危险权限,验证跨库访问被拒,并注意host匹配优先级与连接清理。

创建只读用户并限制到指定数据库
MySQL 里没有“只读角色”这种现成概念,必须手动建用户、授 SELECT 权限,并且明确限定在某个库上,否则容易误授全局权限。常见错误是用 GRANT SELECT ON *.*,这会让用户能查所有库,包括 mysql 系统库,存在信息泄露风险。
实操建议:
- 先用
CREATE USER 'analyst01'@'192.168.1.%' IDENTIFIED BY 'strong_pass_2024';创建用户,注意指定可信 IP 段(比如分析师常用出口 IP),别用'%'开放所有来源 - 再执行
GRANT SELECT ON `sales_db`.* TO 'analyst01'@'192.168.1.%';—— 这里必须用反引号包裹数据库名,尤其当库名含短横或数字时(如prod-v2)会报语法错 - 别漏掉
FLUSH PRIVILEGES;,否则权限不生效;但 MySQL 8.0+ 在多数情况下可省略,仅在直接改系统表后才需强制刷新
禁止写操作:不只是不给 INSERT/UPDATE/DELETE
只授 SELECT 看似安全,但实际还有几个隐蔽入口可能被用来修改数据:比如执行 SELECT ... INTO OUTFILE 可写服务器文件,SELECT ... INTO DUMPFILE 更危险,甚至某些 UDF 或存储过程调用也能绕过权限控制。
实操建议:
- 确认用户没被授予
FILE权限:SHOW GRANTS FOR 'analyst01'@'192.168.1.%';,如果返回里有FILE,立刻用REVOKE FILE ON *.* FROM 'analyst01'@'192.168.1.%';收回 - 检查是否允许创建临时表:
CREATE TEMPORARY TABLES权限虽不直接写业务表,但可能被用于构造中间结果干扰分析逻辑,建议也收回 - MySQL 8.0+ 用户可加
WITH MAX_QUERIES_PER_HOUR 1000之类限制,防暴力扫描或意外全表遍历拖垮库
验证权限是否真正受限
光看 GRANT 语句不保险。MySQL 的权限是叠加生效的,如果用户同时匹配多个 host(比如 'analyst01'@'%' 和 'analyst01'@'192.168.1.%'),会取权限并集,可能意外获得更高权限。
实操建议:
- 用
SELECT user, host FROM mysql.user WHERE user = 'analyst01';查清该用户名下所有 host 记录,删掉冗余的(比如不要留着@'%') - 切到该用户连接后,执行
SELECT DATABASE();确保默认库是目标库;再试INSERT INTO sales_db.orders VALUES (...);,应明确报错ERROR 1142 (42000): INSERT command denied to user - 特别验证跨库查询:
SELECT * FROM information_schema.TABLES LIMIT 1;应允许(只读元数据),但SELECT * FROM other_db.users;必须拒绝 —— 如果没拒绝,说明权限没限定在具体库上
后续维护:权限变更与账号生命周期
分析师换组、离职或项目结束时,很多人只删账号,却忘了回收权限缓存或残留连接。MySQL 不会自动踢掉已存在的连接,旧权限在连接存活期内依然有效。
实操建议:
- 删用户前,先用
KILL命令干掉对应连接:SELECT CONCAT('KILL ',id,';') FROM information_schema.PROCESSLIST WHERE USER='analyst01';,复制结果执行 - 如果用的是 MySQL 8.0+,推荐用角色(
ROLE)管理:先CREATE ROLE 'analyst_readonly';,再GRANT SELECT ON `sales_db`.* TO 'analyst_readonly';,最后GRANT 'analyst_readonly' TO 'analyst01'@'...';—— 后续只需改角色权限,所有成员自动同步 - 定期用
SELECT user, host, account_locked FROM mysql.user WHERE account_locked = 'Y';扫描长期未用但未锁死的账号,避免成为攻击跳板
最易被忽略的是权限继承链和 host 匹配优先级,MySQL 按 user@host 字符串最长匹配原则选权限记录,不是按创建顺序。所以 'analyst01'@'192.168.1.100' 和 'analyst01'@'192.168.1.%' 共存时,前者优先级更高——配置前得想清楚粒度。










