Navicat Cloud的Viewer角色不等于数据库只读,它仅限制编辑Connection配置、Query文件和Data Model导出,不拦截SQL执行;真正只读必须在数据库侧通过GRANT SELECT并REVOKE写权限实现,且需精确匹配用户IP与对象范围。

Navicat Cloud的Viewer角色不等于数据库只读
你在Navicat Cloud后台把成员设为Viewer,他依然能双击连接、打开查询窗口、手写DELETE FROM users并成功执行——只要该连接使用的数据库账号本身有DELETE权限。Viewer只锁三件事:Connection配置不可编辑、保存的Query文件不可修改、Data Model不可导出(除非项目级开启Allow exporting result sets)。它完全不拦截SQL执行,也不向数据库传递任何权限指令。
真正生效的只读必须靠后端数据库账号授权
想让成员“只能查不能删”,必须在MySQL或PostgreSQL里显式授予最小必要权限:
- MySQL:执行
GRANT SELECT ON mydb.report_log TO 'team_user'@'10.20.30.45',再用REVOKE INSERT, UPDATE, DELETE, DROP, ALTER ON mydb.* FROM 'team_user'@'10.20.30.45'显式剔除所有写类权限 - PostgreSQL:先授
CONNECT权限到目标database,再授USAGE到schema(如public),最后才授SELECT ON TABLE——漏任一环,\dt或SHOW TABLES都会返回空 - 主机字段
'host'必须填合作方固定出口IP或CIDR段(如'203.0.113.45'),绝不能填'%';填错会导致权限不匹配或过度开放 - 执行完
GRANT/REVOKE后,MySQL 5.7/8.0.29之前版本必须手动运行FLUSH PRIVILEGES
Navicat Cloud权限与数据库权限必须同步生效
常见失效场景不是Cloud没点对,而是底层权限链断了:
- Navicat Cloud里设了
Viewer,但数据库账号是'user'@'localhost',而成员从10.20.30.45连进来——匹配失败,直接拒绝连接 - 测试库配好了权限,上线后UAT/生产环境的
mysql.user表是独立的,没手动或脚本重复执行GRANT,权限自然不生效 - 成员改用手机热点或云函数(如AWS Lambda)连接,IP不固定,
@'10.20.30.45'直接失效;此时得配数据库白名单+应用层代理,或换用临时凭证(如IAM认证),不能妥协填@'%'
细粒度控制需绕过Navicat新建用户向导
Navicat的「新建用户」向导只支持库级粗粒度授权(如mydb.*),无法指定单表、列、IP段。要实现真正安全的只读,必须关掉向导,手动执行SQL:
- 表级只读:
GRANT SELECT ON mydb.sales_summary TO 'reporter'@'203.0.113.45' - 列级只读(MySQL 8.0+):
GRANT SELECT(id, created_at) ON mydb.orders TO 'dev'@'10.20.30.0/24'——注意括号不能漏,写成SELECT id, created_at会报ERROR 1064 - 权限变更后,成员需重启Navicat或等待最长15分钟后台轮询,才可能刷新界面可见性
真正的只读防线不在Navicat Cloud界面里,而在GRANT语句的ON子句是否精确到表、TO子句的@'ip'是否锁定来源、以及REVOKE是否显式剥离所有非SELECT权限——这三处任何一个字符出错,整个只读策略就形同虚设。


















