只读账号必须显式授予GRANT SELECT权限并限定库表范围,禁用LOCK TABLES等隐式写权限,补USAGE确保登录,8.0+需显式授权information_schema.TABLES且设DEFAULT ROLE激活。

只读账号必须用 GRANT SELECT,不是禁用写权限
MySQL 没有“只读用户”这个内置类型,所谓只读,就是只给 SELECT 权限。靠 REVOKE INSERT, UPDATE 等方式清理权限是危险的:容易漏掉 TRUNCATE、LOCK TABLES 或 EXECUTE(如果存在函数),反而留下后门。正确做法是白名单思维——只显式授予 SELECT,其余一律不给。
常见错误现象:SHOW GRANTS FOR 'report_user'@'%' 输出里出现 INSERT 或 USAGE 以外的任何权限,说明授权不干净。
-
GRANT SELECT必须带明确范围,例如GRANT SELECT ON `report_db`.*;不能写GRANT SELECT ON *.*,否则会意外放开mysql、INFORMATION_SCHEMA等系统库 - 库名含短横或关键字(如
order_db)必须用反引号包裹,否则语法报错 - MySQL 8.0 不支持在
CREATE USER语句里直接GRANT,必须拆成两步:先CREATE USER,再GRANT
创建用户时必须指定 mysql_native_password 插件
MySQL 8.0 默认用 caching_sha2_password 插件,但很多报表工具(比如旧版 Tableau、某些 Python 2.7 的 mysqlclient)不兼容,会报错:authentication plugin 'caching_sha2_password' cannot be loaded。这不是权限问题,是连接握手失败。
实操建议:
- 查当前插件:
SELECT user, host, plugin FROM mysql.user WHERE user = 'report_user' - 建用户时显式指定:
CREATE USER 'report_user'@'192.168.20.%' IDENTIFIED WITH mysql_native_password BY 'R3p0rt!2024' - 主机段用
192.168.20.%限定内网报表服务器 IP 段,别用%——防止被扫描利用
必须额外授予 INFORMATION_SCHEMA.SELECT
报表系统常执行 SHOW CREATE TABLE orders 或自动探测字段类型,这依赖 INFORMATION_SCHEMA。但默认只授 SELECT ON report_db.* 时,用户访问 INFORMATION_SCHEMA 会失败,报错:ERROR 1142 (42000): SELECT command denied。
解决方案是额外授权:GRANT SELECT ON INFORMATION_SCHEMA.* TO 'report_user'@'192.168.20.%'
- 不需要给
performance_schema或sys,报表基本用不到 - 即使授了
INFORMATION_SCHEMA,普通用户也查不到mysql.user这类敏感表,MySQL 内部做了行级过滤,无需担心 -
SHOW CREATE TABLE失败,八成是因为缺这条授权,不是权限没给全
验证时注意 CURRENT_USER() 和新连接
权限修改后,必须用新连接登录验证,别复用旧会话(旧连接缓存权限快照)。更关键的是,CURRENT_USER() 才反映实际匹配到哪个账号,而 USER() 只显示你“声称”的登录名。
- 执行
SELECT CURRENT_USER(),确认返回的是'report_user'@'192.168.20.x'而不是'report_user'@'%'或'report_user'@'localhost' - 再执行
SHOW GRANTS FOR CURRENT_USER(),看输出是否只有SELECT权限,且范围精确到业务库 - 测试
SELECT COUNT(*) FROM report_db.users→ 应成功;INSERT INTO report_db.users(name) VALUES('test')→ 必须报ERROR 1142;SELECT FOR UPDATE→ 必然失败(这是预期行为,不是配置错误)
最容易被忽略的是 host 匹配细节:写成 'report_user'@'localhost' 却用 127.0.0.1 连接,或客户端走 socket 却没建 localhost 账号——这两者在 MySQL 里算不同用户,权限不互通。


















