mysql中只需显式授予insert、update、delete、select权限,不授予alter/drop等ddl权限即可实现dml-only控制;grant all会意外赋予高危权限,应避免使用。
mysql 里怎么只给 insert/update/delete 权限,不给 alter/drop
直接结论:用 grant 显式授予 insert、update、delete、select 权限,**完全不提** alter、drop、create 这类 ddl 权限,mysql 就不会自动赋予它们。
常见错误是顺手写 GRANT ALL PRIVILEGES,或者用图形化工具点“全选权限”,结果用户能删字段、改类型、清空表——这不是权限没设好,是根本没想清楚“ALL”到底包含什么。
GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.mytable TO 'user'@'%';- 别用
GRANT ALL ON ...,哪怕只是临时测试;ALL在 MySQL 8.0+ 包含ALTER ROUTINE、EVENT等隐性权限,远超 DML 范围 - 执行完记得
FLUSH PRIVILEGES;(仅在直接操作mysql系统表后才强制需要,但养成习惯没坏处)
PostgreSQL 怎么禁用 ALTER TABLE 但允许 UPDATE
PostgreSQL 的权限模型更细,UPDATE 属于表级权限,ALTER TABLE 属于 schema 级或 owner 级操作,**默认就不带**——只要不把用户加进 owner 角色、不显式 GRANT ALTER ON SCHEMA,用户就动不了结构。
真正容易翻车的是:用户被误设为表 OWNER,或者被加入有 CREATEROLE / CREATEDB 的角色(这些超级权限会绕过大部分限制)。
- 确认用户不是表 owner:
SELECT tableowner FROM pg_tables WHERE tablename = 'mytable'; - 撤销可能越权的角色:
REVOKE CREATEROLE, CREATEDB FROM user_name; - 只授必要权限:
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE mytable TO user_name; - 注意:PostgreSQL 没有“DML-only”快捷权限组,必须逐个列明,漏掉
SELECT可能导致某些 ORM 执行UPDATE前先查主键失败
用户执行 ALTER TABLE 报错 ERROR 1142 (42000): ALTER command denied 是好事
这个报错不是配置失败,恰恰说明权限控制生效了。MySQL 在拒绝 DDL 时固定返回这个错误码,和用户有没有 SELECT 权限无关,只取决于是否拥有对应 DDL 权限。
但如果用户还能通过其他方式改结构,比如用 mysqldump --no-create-info 导出再重建,那问题不在权限,而在流程管控——数据库权限管不住本地导出行为。
- 检查错误日志里是否真出现该报错,而不是用户静默失败(有些客户端不显示 SQL 错误)
- 确认用户连接时用的是你授权的账号,不是被意外切换到
root或其他高权限账号 - 如果应用用连接池,检查池配置是否复用了管理员连接(例如 HikariCP 的
connection-init-sql里写了SET ROLE)
SQL Server 收回 ALTER 权限要小心 VIEW DEFINITION
SQL Server 默认新用户可能继承 public 角色的 VIEW DEFINITION 权限,这会让用户能 sp_help 查字段、甚至看到加密存储过程逻辑——虽然不能改表,但能反推结构设计。
真正锁死结构修改,除了不给 ALTER,还得清理这类“旁路可见性”权限。
- 显式拒权:
DENY ALTER ON OBJECT::mytable TO [user_name]; - 收回元数据可见性:
DENY VIEW DEFINITION ON OBJECT::mytable TO [user_name]; - 注意
DENY优先级高于GRANT,哪怕用户属于某个有VIEW DEFINITION的角色,单独DENY也生效 - SQL Server 不支持对单个字段收权限,所以
DENY只能作用于整个表或视图
权限粒度越细,越容易漏掉一个隐性依赖项——比如 PostgreSQL 用户没被给 USAGE 权限到 schema,连表名都查不到;或者 MySQL 用户缺少 SELECT 却被应用要求先 SELECT FOR UPDATE。动手前先想清楚:用户到底要做什么动作,而不是“看起来像只读”。










