mysql如何配置只读用户_mysql只读权限设置

来源:这里教程网 时间:2026-02-28 20:49:39 作者:

只读用户必须显式拒绝写权限,不能只靠 GRANT SELECT

MySQL 的权限模型是“显式授权”,

GRANT SELECT
不代表自动禁止
INSERT
/
UPDATE
/
DELETE
;如果用户之前被授予过全局或库级写权限(比如通过
GRANT ALL PRIVILEGES
),仅执行
GRANT SELECT
不会撤销已有权限。必须先
REVOKE
写操作权限,再
GRANT SELECT

常见错误现象:用户仍能执行

DELETE FROM t1
,即使你只运行了
GRANT SELECT ON db1.* TO 'ro_user'@'%'
—— 很可能该用户继承了
mysql.user
表中残留的旧权限。

检查当前权限:运行
SHOW GRANTS FOR 'ro_user'@'%'
彻底清理:先执行
REVOKE INSERT, UPDATE, DELETE, DROP, CREATE, ALTER, INDEX, LOCK TABLES, EXECUTE ON *.* FROM 'ro_user'@'%'
再授只读:
GRANT SELECT ON `db1`.* TO 'ro_user'@'%'
最后别忘:
FLUSH PRIVILEGES

跨库查询时只读权限不自动继承

SELECT
权限是按库/表粒度控制的。用户对
db1
SELECT
权限,不代表能查
db2
,也不代表能查
db1
中的
INFORMATION_SCHEMA
performance_schema
—— 这些系统库需单独授权(通常不建议开放)。

使用场景:应用连接后执行

SELECT * FROM db2.t2
报错
ERROR 1142 (42000): SELECT command denied to user
,但用户明明在
db2
上跑过
USE db2

若需跨多个业务库只读,逐个授权:
GRANT SELECT ON `db2`.* TO 'ro_user'@'%'
避免用
GRANT SELECT ON *.*
(等同于所有库可读,含敏感系统库)
注意反引号:库名含短横线或关键字时必须用
`db-name`
,否则语法报错

只读用户无法执行 SHOW CREATE TABLE?检查 USAGE + SELECT 组合

很多 ORM 或监控工具会尝试执行

SHOW CREATE TABLE t1
SHOW FULL COLUMNS FROM t1
。这类语句底层依赖
SELECT
权限(查
information_schema
表),但 MySQL 8.0+ 对
information_schema
的访问受更细粒度限制。

典型错误:用户能

SELECT * FROM t1
,但执行
SHOW CREATE TABLE t1
ERROR 1142 (42000): SHOW command denied to user

MySQL 5.7:确保用户对
information_schema
SELECT
(默认所有用户都有,除非显式
REVOKE
过)
MySQL 8.0+:
information_schema
默认不可写,但部分元数据操作需
USAGE
+ 显式
SELECT
;稳妥做法是加一句:
GRANT SELECT ON `information_schema`.`TABLES` TO 'ro_user'@'%'
注意:不要授
information_schema
全库,只需
TABLES
COLUMNS
STATISTICS
等必要表

应用连接后仍报权限错误?检查 host 匹配和 SQL_MODE

权限记录由

User
+
Host
共同决定。
'ro_user'@'localhost'
'ro_user'@'%'
是两个完全独立的账号,哪怕密码相同,权限也互不影响。另外,某些 SQL_MODE(如
STRICT_TRANS_TABLES
)虽不直接影响权限,但会让隐式类型转换失败,误判为“无权访问”。

确认连接来源 IP 是否匹配
Host
字段(用
SELECT USER(), CURRENT_USER()
查看实际匹配的账号)
测试时用
mysql -u ro_user -h 127.0.0.1 -p
(走 TCP)而非
mysql -u ro_user -p
(走 socket,默认 host= localhost)
检查是否启用了
read_only=ON
全局设置:它只限制非 SUPER 用户的写操作,但不会替代细粒度权限控制;两者应配合使用,而非互相替代

复杂点在于权限生效链路:SQL 解析 → 账号匹配 → 权限查表(mysql.tables_priv / mysql.columns_priv / mysql.db)→ 缓存校验。中间任何一环配置偏差,都会导致“明明授了权却没效”。最易忽略的是

CURRENT_USER()
返回值与预期不符,以及未执行
FLUSH PRIVILEGES
后直接测试。

相关推荐