真正安全的只读账号只需SELECT权限,严禁授予SHOW VIEW、LOCK TABLES、PROCESS等额外权限;跨库查询需对所有涉及库显式授权SELECT;必须避免GRANT SELECT ON .等危险写法,并执行FLUSH PRIVILEGES确保生效。

只读账号到底需要哪些权限
MySQL 的“只读”不是单个权限开关,而是组合控制。真正安全的只读账号只需 SELECT 权限,**不能给 SHOW VIEW、LOCK TABLES、PROCESS 等看似无害的权限**——它们可能被用来探测表结构或阻塞操作。
常见误操作是顺手加上 USAGE 或漏掉 WITH GRANT OPTION 的禁用(必须显式不加,否则默认不可继承)。
-
SELECT是唯一必需权限;其他如SHOW DATABASES、EXECUTE都应排除 - 如果数据库含视图,且需查询视图内容,才额外加
SHOW VIEW(仅当视图定义不可见时才暴露风险) - 跨库查询(如
SELECT * FROM db1.t1 JOIN db2.t2)要求对所有涉及库都授予SELECT
GRANT 语句写法与典型错误
正确写法要明确指定库名和表名,避免使用通配符 * 意外覆盖系统库。下面这条命令创建一个只能查 app_db 库下所有表的账号:
GRANT SELECT ON `app_db`.* TO 'ro_user'@'192.168.1.%' IDENTIFIED BY 'strong-pass-2024';
常见错误包括:
- 写成
GRANT SELECT ON *.*—— 这会赋予对所有库(含mysql系统库)的读取权,极其危险 - 忘记执行
FLUSH PRIVILEGES;—— 权限变更不会立即生效(但 MySQL 5.7+ 在多数情况下可省略,仍建议执行以确保) - 用单引号包裹数据库名,如
'app_db'.*—— 语法报错,必须用反引号或不加引号(无特殊字符时) - 用户名带域名却没加引号,如
ro_user@localhost写成ro_user@%.—— 匹配失败导致授权无效
验证权限是否真的受限
别只信 GRANT 语句执行成功。登录后立刻测试边界行为:
- 执行
INSERT INTO t1 VALUES (1);→ 应报错ERROR 1142 (42000): INSERT command denied - 执行
SHOW CREATE TABLE mysql.user;→ 应报错ERROR 1142 (42000): SHOW command denied(除非你真给了mysql库权限) - 执行
SELECT * FROM information_schema.TABLES LIMIT 1;→ 默认允许(因为information_schema是只读元数据),但若业务不需要,可通过启动参数--skip-show-databases或限制连接来源 IP 控制
注意:SELECT 权限不包含对 performance_schema 或 sys 的访问,但某些旧版本默认开放——检查 SELECT 是否被隐式授予这些库。
生产环境必须做的加固动作
最小权限只是起点。上线前至少补这三步:
- 确认账号密码强度:用
ALTER USER 'ro_user'@'%' REQUIRE SSL;强制加密传输(尤其跨公网) - 限制登录 IP 范围,避免写成
'%',改用具体子网如'10.10.20.%'或跳板机 IP - 定期审计:用
SELECT User, Host, Select_priv FROM mysql.user WHERE User = 'ro_user';核对权限字段,防止被误改
最常被忽略的是:应用配置里硬编码了 root 密码,开发为“方便调试”悄悄开了全库 SELECT 权限,然后忘了关——这类账号往往比弱密码更早成为突破口。


















