mysql如何创建只读权限账户 通过GRANT SELECT实现权限管控实战案例|Duuu笔记
GRANT SELECT必须写database_name.而非仅database_name,因MySQL不支持直接授予数据库对象SELECT权限;漏掉.会静默失败,且.授权极危险,应逐库显式授权并注意performance_schema等系统表暴露风险。
创建只读账户时,GRANT SELECT 为什么不能只写数据库名?
MySQL 的
GRANT SELECT
权限必须明确作用范围,只写
database_name.*
是合法的,但若漏掉末尾的
.*
(比如写成
database_name
),命令会静默失败——不报错,也不生效。这是因为 MySQL 把不带通配符的数据库名当作“数据库级对象名”,而
SELECT
权限不支持直接授予数据库对象本身,只支持表(
db.table
)或库下所有表(
db.*
)。
实操建议:
始终用
GRANT SELECT ON database_name.* TO 'user'@'host';
,别省略
.*
如果只想限制到某些表,写成
GRANT SELECT ON database_name.table1 TO ...
、
GRANT SELECT ON database_name.table2 TO ...
,不能合并成一条语句授多个表
执行后必须跟
FLUSH PRIVILEGES;
,否则权限不会立即生效(尤其在非 super 用户修改后)
只读账户连不上?检查 host 匹配和 authentication plugin
常见错误现象是:用户创建成功、权限也 GRANT 了,但客户端连接时报
Access denied for user 'ro_user'@'192.168.1.100'
。这通常不是权限问题,而是
host
字段没对上,或者 MySQL 8.0+ 默认用了
caching_sha2_password
插件,而旧客户端不支持。
实操建议:
创建时显式指定 host:
CREATE USER 'ro_user'@'192.168.1.%' IDENTIFIED BY 'pwd';
,避免依赖默认的
%
(可能被防火墙或网络策略拦截)
MySQL 8.0+ 若需兼容老客户端,建用户时加
IDENTIFIED WITH mysql_native_password BY 'pwd'
确认用户实际从哪个 IP 连入:在客户端执行
SELECT USER(), CURRENT_USER();
,前者是“你声称是谁”,后者是“MySQL 认为你是谁”,两者不一致就说明 host 匹配失败
GRANT SELECT ON *.* 有风险吗?
可以,但非常危险。
GRANT SELECT ON *.*
看似方便,实际会把所有库(包括
mysql
、
information_schema
、
performance_schema
)的表都开放只读。攻击者能从中提取用户哈希、权限配置、SQL 模式等敏感元数据。
Action Figure AI
借助Action Figure AI的先进技术,瞬间将照片转化为定制动作人偶。
下载
实操建议:
永远不要对生产环境用
*.*
,哪怕只是临时查问题
如果真要跨库只读,逐个显式授权:
GRANT SELECT ON db1.* TO ...
、
GRANT SELECT ON db2.* TO ...
注意
information_schema
默认对所有用户可读,但部分视图(如
PROCESSLIST
)需要额外权限,
GRANT SELECT ON *.*
会意外放开这些
只读账户还能执行哪些“非查询”操作?
SELECT
权限本身不包含事务控制、锁表、DDL 等能力,但仍有几个容易被忽略的“旁路动作”:
实操建议:
仍可执行
SHOW CREATE TABLE
、
SHOW INDEX
、
EXPLAIN
—— 它们依赖表级
SELECT
权限,不算额外授权
可调用某些内置函数,如
NOW()
、
USER()
、
DATABASE()
,但不能调用写入型函数(如
UUID_SHORT()
在某些版本会触发内部写)
不能执行
SELECT ... INTO OUTFILE
,除非额外授予
FILE
权限(极不推荐)
MySQL 8.0+ 中,即使只有
SELECT
,也能通过
SELECT * FROM performance_schema.events_statements_current
看到其他用户的 SQL(需确认
performance_schema
是否启用且未禁用相关表)
真正严格的只读,不只是关掉 INSERT/UPDATE/DELETE,还得盯住元数据访问和系统表暴露面。权限颗粒度越细,越容易漏掉一个点。
