Navicat界面“只读连接”或Team Viewer角色仅限制客户端操作,不控制数据库权限;真正只读必须在MySQL/PostgreSQL中通过GRANT SELECT并显式REVOKE INSERT、UPDATE等写权限实现,且需精确匹配用户IP、表名及层级权限。

Navicat界面设“只读连接”或Team Viewer角色根本不管用
你在连接属性里勾选“只读连接”,或者在Navicat Cloud后台把成员设为Viewer,都不影响SQL执行。他照样能双击连接、打开查询窗口、手写DELETE FROM orders并成功提交——只要数据库账号本身有DELETE权限。Viewer只锁三件事:Connection配置不可编辑、保存的Query文件不可修改、Data Model不可导出(除非项目级开了Allow exporting result sets)。它不向数据库发任何权限指令,也不拦截语句。
真正生效的只读必须由数据库账号权限决定
外部合作团队能否只读,完全取决于你给他们的数据库账号被GRANT了什么、又被REVOKE了什么。关键不是Navicat怎么点,而是MySQL或PostgreSQL里那几条授权语句是否精准:
- MySQL表级只读:必须手动执行
GRANT SELECT ON mydb.sales_summary TO 'partner'@'203.0.113.45',不能依赖Navicat「新建用户」向导(它只支持mydb.*库级粗粒度) - 显式剔除所有写权限:
REVOKE INSERT, UPDATE, DELETE, DROP, ALTER, CREATE TEMPORARY TABLE ON mydb.* FROM 'partner'@'203.0.113.45'——漏掉CREATE TEMPORARY TABLE可能引发临时表空间耗尽事故 - MySQL 8.0.29之前版本必须跟一句
FLUSH PRIVILEGES,否则权限不生效 - PostgreSQL需分层授权:先
GRANT CONNECT ON DATABASE analytics_db TO partner,再GRANT USAGE ON SCHEMA public TO partner,最后才GRANT SELECT ON TABLE public.sales_summary TO partner;漏任一环,\dt或SHOW TABLES都返回空
host字段填的是合作方IP,不是你的数据库服务器地址
很多人把user@'host'里的host误解成数据库所在机器的IP,结果填错导致权限失效或过度开放。这个host控制“谁可以连进来”,直接影响权限匹配逻辑:
- 填
'%'= 允许任意公网IP连接 → 生产环境严禁 - 填
'203.0.113.45'或'10.20.30.0/24'= 限定可信出口IP或网段 → 推荐做法 - 合作方用手机热点、云函数(如AWS Lambda)等动态IP接入时,
@'203.0.113.45'会直接失效;此时不能妥协填@'%',得配数据库白名单+应用层代理,或换用临时凭证(如IAM认证)
验证只读是否真生效,不能只看Navicat界面
权限配置完,必须从合作方真实环境连一次,用他们实际用的账号和IP测试。常见失效场景不是Navicat没点对,而是底层权限链断了:
- Navicat Cloud设了
Viewer,但数据库账号是'partner'@'localhost',而对方从203.0.113.45连 → 匹配失败,直接拒绝连接 - 测试库配好了,UAT/生产环境的
mysql.user表是独立的,没手动或脚本重复执行GRANT→ 权限自然不生效 - 用
SELECT USER(), CURRENT_USER()确认登录身份是否匹配预期的'partner'@'203.0.113.45';再试INSERT INTO sales_summary VALUES (...),应明确报错ERROR 1142 (42000): INSERT command denied
临时通道最危险的盲区,往往不在“开了什么权限”,而在“没关什么权限”——比如忘了REVOKE CREATE TEMPORARY TABLE,或者误授了USAGE到整个information_schema。每一条GRANT都要对应一条REVOKE,否则就等于留了后门。


















