只读用户必须授予哪些权限
MySQL 的只读访问不是靠一个
READ ONLY权限实现的,而是通过显式授予有限的、不带写能力的权限组合。核心是:只给
SELECT,不给
INSERT、
UPDATE、
DELETE、
DROP、
CREATE、
ALTER等任何修改类权限。
常见错误是误加
SHOW VIEW或
LOCK TABLES——它们虽不直接写数据,但可能暴露结构或阻塞业务,生产环境应按需开启。
SELECT是唯一必需的基础权限 如需查看表结构,额外加
SHOW CREATE TABLE(注意:不是
SHOW DATABASES) 如需执行
EXPLAIN或查看执行计划,需
PROCESS权限(仅限本地调试,线上慎开) 跨库 JOIN 查询时,目标库所有涉及的表都要单独授权
SELECT
创建最小权限只读用户的完整命令
假设数据库名为
app_db,用户名为
ro_user,密码为
'secure_ro_pass',只允许从内网
192.168.10.%连接:
CREATE USER 'ro_user'@'192.168.10.%' IDENTIFIED BY 'secure_ro_pass'; GRANT SELECT ON app_db.* TO 'ro_user'@'192.168.10.%'; FLUSH PRIVILEGES;
关键点:
不要用GRANT SELECT ON *.*—— 这会暴露系统库(如
information_schema),存在信息泄露风险 主机名尽量具体,避免用
'%';若必须通配,请确认网络层已限制访问源
FLUSH PRIVILEGES在大多数情况下非必需(只要用
GRANT语句就自动生效),但部分旧版本或特殊部署下建议保留
验证只读权限是否生效
用新用户登录后,执行以下检查:
能成功运行SELECT COUNT(*) FROM app_db.users;执行
INSERT INTO app_db.users (...) VALUES (...);应报错:
ERROR 1142 (42000): INSERT command denied to user执行
SHOW GRANTS FOR CURRENT_USER;确认返回结果中只有
SELECT权限,无其他 DML/DCL 权限 尝试
USE mysql;后查
user表——应因无权限拒绝,而非返回空结果(空结果说明有权限但没数据,是严重误配置)
应用连接池中要注意的兼容性问题
某些 ORM 或连接池(如 HikariCP、Druid)在初始化时会默认执行
SELECT 1或
SELECT @@sql_mode等探测语句。这些语句本身没问题,但若连接字符串中指定了
database=xxx而该库未被授权,就会连接失败。
解决方案:
确保GRANT SELECT ON <db_name>.*</db_name>中的库名与应用配置完全一致(大小写敏感取决于 OS 和
lower_case_table_names设置) 避免在 JDBC URL 中指定不存在或未授权的
database参数;可改用
useSSL=false&serverTimezone=UTC等纯连接参数 Spring Boot + MyBatis 场景下,
spring.sql.init.mode=never必须显式设置,否则启动时可能尝试建表
最易忽略的是:MySQL 8.0+ 默认启用
caching_sha2_password插件,而旧版客户端可能不支持——此时即使权限正确,也会卡在认证阶段,报错类似
Public Key Retrieval is not allowed。需确认客户端驱动版本或改用
mysql_native_password认证方式。
