Skip to content
VDS · 数据库

数据库中的用户与权限

如何在 MySQL 和 PostgreSQL 中为每个应用创建单独的用户、授予最小权限,并确认没有多余权限被允许。

更新于 2026年8月23日

以 root 或 postgres 身份运行的应用程序,一旦出现第一个漏洞,就会把机器上的所有数据库拱手交给攻击者。为项目创建专用用户,只授予其自身 schema 的权限,可以将损失限制在一个项目之内。

MySQL 和 MariaDB

这里的用户是“名称 + 主机”的组合,这也是最容易混淆的地方:

CREATE USER 'shop'@'localhost' IDENTIFIED BY 'long-random-password';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'shop'@'localhost';
FLUSH PRIVILEGES;

'shop'@'localhost' 和 'shop'@'%' 是两个不同的用户,密码也各不相同。除非确有必要,不要创建主机为 % 的记录:它允许从任意地址登录。

只有在执行迁移时才需要结构层面的权限:

GRANT CREATE, ALTER, DROP, INDEX, REFERENCES ON shop.* TO 'shop_migrate'@'localhost';

将应用角色与迁移角色分开是很好的做法:这样普通查询在物理上就不可能删除表。

检查:

SELECT user, host FROM mysql.user;
SHOW GRANTS FOR 'shop'@'localhost';

修改密码并删除:

ALTER USER 'shop'@'localhost' IDENTIFIED BY 'new-password';
DROP USER 'shop'@'localhost';

PostgreSQL

角色及其对数据库和 schema 的权限:

CREATE ROLE shop WITH LOGIN PASSWORD 'long-random-password';
CREATE DATABASE shop OWNER shop;
REVOKE ALL ON DATABASE shop FROM PUBLIC;

对于只读角色(报表、分析、监控面板):

CREATE ROLE reader WITH LOGIN PASSWORD '...';
GRANT CONNECT ON DATABASE shop TO reader;
GRANT USAGE ON SCHEMA public TO reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT ON TABLES TO reader;

最后一行是必须的:没有它,角色将看不到授予权限之后创建的表,一个月后报表就会因为新数据而出错。

检查:

\du
\l
\dp

必须锁定的内容

  • 任何应用角色都不是超级用户。
  • 每个项目都有自己的数据库和自己的用户。
  • 密码要足够长且随机,不同项目使用不同的密码。
  • 只对需要外部登录的地址开放外部登录——远程访问。
  • MySQL 中不能有匿名用户,也不能有测试数据库:mariadb-secure-installation 会完成这项工作。

常见错误

现象原因
密码正确却提示 Access denied匹配到了另一条主机规则,例如 ''@'localhost'
已授予权限,但 SELECT 无法执行PostgreSQL 缺少 USAGE ON SCHEMA
角色看不到新建的表未设置 DEFAULT PRIVILEGES
迁移失败时应用程序删除了所有数据应用角色拥有 DROP 权限
密码出现在命令历史中请从文件设置密码,并清除 ~/.mysql_history

请将数据库密码存放在权限为 600 的服务环境变量文件中,而不是写在代码里。一旦泄露,您只需修改一行并重启,而不必重建整个项目。