mysql 8.0为只读副本配置账户必须显式创建用户(指定mysql_native_password插件)、限定精确host、授予select及replication client/process权限、revoke所有写权限和super、补usage,并用新连接验证current_user()与show grants。

MySQL 8.0 中为只读副本配置只读账户,不能只靠 GRANT SELECT 就完事——必须显式清理残留权限、补 USAGE、限定 host、避开 caching_sha2_password 兼容问题,否则副本连接会静默失败或指标采集为空。
CREATE USER 必须指定 mysql_native_password 插件
MySQL 8.0+ 默认用 caching_sha2_password,但多数复制监控工具(如 mysqld_exporter v0.14.x、旧版 pt-table-checksum)不支持,连不上时只报 Access denied for user,不提示认证方式问题。
- 正确写法:
CREATE USER 'repl_ro'@'10.10.20.5' IDENTIFIED WITH mysql_native_password BY 'StrongPass2026!'; - host 必须是副本实际出站 IP(比如副本服务器的内网 IP),不是
'%',也不是容器网段(如172.18.0.0/16) - 同机部署(如本地
mysqld_exporter)优先用'localhost',走 Unix socket,绕过 DNS 和网络层干扰
GRANT SELECT 后必须显式 REVOKE 写类权限
只执行 GRANT SELECT ON `myapp`.* TO 'repl_ro'@'10.10.20.5'; 不等于只读。如果该用户之前被授予过 ALL PRIVILEGES 或继承了角色权限,INSERT/DROP/LOCK TABLES 等仍有效。
- 先查当前权限:
SHOW GRANTS FOR 'repl_ro'@'10.10.20.5'; - 强制清理(关键):
REVOKE INSERT, UPDATE, DELETE, DROP, CREATE, ALTER, INDEX, LOCK TABLES, EXECUTE, TRUNCATE, CREATE TEMPORARY TABLES ON `myapp`.* FROM 'repl_ro'@'10.10.20.5'; - 再授只读:
GRANT SELECT ON `myapp`.* TO 'repl_ro'@'10.10.20.5'; - 检查是否残留
SUPER:SELECT Super_priv FROM mysql.user WHERE User = 'repl_ro' AND Host = '10.10.20.5';,若为Y,立刻REVOKE SUPER ON *.* FROM 'repl_ro'@'10.10.20.5';
副本常用操作需要额外系统库权限
只读副本常需执行 SHOW SLAVE STATUS、SHOW PROCESSLIST、SHOW CREATE TABLE,这些依赖全局权限和 information_schema 查询,仅业务库 SELECT 不够。
-
REPLICATION CLIENT:查复制状态必需,GRANT REPLICATION CLIENT ON *.* TO 'repl_ro'@'10.10.20.5'; -
PROCESS:查线程列表必需,GRANT PROCESS ON *.* TO 'repl_ro'@'10.10.20.5'; -
information_schema.TABLES:支持SHOW CREATE TABLE,GRANT SELECT ON `information_schema`.`TABLES` TO 'repl_ro'@'10.10.20.5'; - 别碰
performance_schema:除非你明确要采集慢查询指标;若不需要,不要授权,避免暴露events_statements_summary_by_digest等敏感摘要
验证时必须用新连接 + CURRENT_USER()
权限变更后复用旧连接会缓存旧权限快照,导致验证失真。必须新开连接,并确认匹配的是你刚创建的账号。
- 登录后立刻执行:
SELECT CURRENT_USER();—— 看输出是否为'repl_ro'@'10.10.20.5' - 再查权限:
SHOW GRANTS FOR CURRENT_USER();—— 输出里应只有SELECT、REPLICATION CLIENT、PROCESS、USAGE,无任何INSERT/UPDATE/SUPER - 测试行为:
SELECT COUNT(*) FROM myapp.users;(成功) vsINSERT INTO myapp.users(id) VALUES(1);(报ERROR 1142) - 别忘了
USAGE:漏掉它会导致连都连不上,错误仍是Access denied,和密码无关
最容易被忽略的是 host 匹配精度和 mysql_native_password 插件指定——这两个点一错,整个配置就卡在连接层,后续所有权限调试都白忙。











