PostgreSQL 中限制用户仅通过 localhost Unix socket 连接,需在 pg_hba.conf 中用 local 行配 peer 认证、host 行拒绝 127.0.0.1/::1,并设 listen_addresses 为空;MySQL 通过 CREATE USER 'u'@'localhost' 实现;Redis 需设 port 0 且清空 bind,启用 unixsocket。
PostgreSQL 中如何限制用户只能通过 localhost 的 Unix socket 连接
postgresql 默认允许本地 socket 和 tcp 连接混用,仅靠 pg_hba.conf 里写 local 并不能阻止用户走 127.0.0.1(即 tcp loopback)连进来——这会绕过 socket 级别的隔离。真要“仅限本地 socket”,得从连接来源和认证规则双侧卡死。
实操建议:
-
pg_hba.conf中明确区分两类规则:用local行处理 Unix socket,用host行拒掉所有 IPv4/IPv6 的127.0.0.1和::1——哪怕它们物理上也在本机 - 对目标用户(比如
app_local),local行的auth-method推荐用peer(Linux)或scram-sha-256+unix_socket_directories配合文件权限控制,避免密码泄露面扩大 - 确认
postgresql.conf中listen_addresses设为''(空字符串)或至少不包含127.0.0.1;否则即使pg_hba.conf拒绝了,内核层仍可能收包
MySQL 8.0+ 创建只响应 /var/run/mysqld/mysqld.sock 的账号
MySQL 没有原生的“仅 socket”账号类型,但可通过 host 字段精准匹配 socket 连接行为:当客户端用 -S 或 localhost 作为 host 连接时,MySQL 会优先走 socket(前提是 socket 文件存在),且此时 user@'localhost' 这条记录会被命中——注意,这是特例,不是 DNS 解析结果。
关键陷阱:
- 不要创建
user@'127.0.0.1',它强制走 TCP;也不要依赖user@'::1',IPv6 loopback 同样是网络栈路径 - 必须删掉或注释掉默认的
user@'%'和user@'127.0.0.1'记录,否则用户换种方式连就逃逸了 - 创建账号时显式指定
CREATE USER 'app_sock'@'localhost' IDENTIFIED BY 'xxx';,这里的'localhost'是字面量,不是通配符 - 验证方式:用
mysql -u app_sock -p -S /var/run/mysqld/mysqld.sock能进,而mysql -u app_sock -p -h 127.0.0.1必须报Access denied
Redis 启动时禁用 TCP 监听,只留 /tmp/redis.sock
Redis 的 bind 和 port 是两套开关。设 port 0 只禁 TCP 端口,但若 bind 仍列了 127.0.0.1,某些旧版本(如 6.x 之前)仍可能监听;真正干净的做法是两者都关,再开 socket。
配置要点:
-
port 0(必须,不是注释掉) -
bind行全部删掉或留空,不要写bind 127.0.0.1 - 启用
unixsocket /tmp/redis.sock和unixsocketperm 700(权限必须严格,否则同主机其他用户可连) - 客户端连接时必须显式用
-s /tmp/redis.sock,用-h localhost会失败——因为没开 TCP,DNS 解析也救不了
为什么 ss -ltn 还能看到 :6379 或 :5432?
常见错觉:以为改完配置 reload 就万事大吉。其实 PostgreSQL/MySQL/Redis 的 socket-only 模式,要求服务进程完全不绑定任何 TCP 地址。如果 ss -ltn | grep :5432 仍有输出,说明 listen_addresses、bind 或 port 没生效,或者服务根本没 reload 成功(systemd 下常因未执行 sudo systemctl daemon-reload 或漏掉 sudo systemctl restart postgresql)。
排查顺序:
- 查进程实际参数:
ps aux | grep postgres,看有没有-c listen_addresses=...出现在命令行里 - 查日志:
journalctl -u postgresql --since "1 hour ago" | grep -i "listening on",确认启动时是否真跳过了 TCP - 别信配置文件名,Redis 的
redis.conf可能被/etc/redis/redis.conf和/etc/redis/redis-server.conf同时引用,优先级容易搞混
最硬的验证:在另一台机器上 telnet your-server 5432,连不上才算过关。本地 nc -zv 127.0.0.1 5432 也该失败——这才是 socket-only 的真实边界。

















