有个朋友之前为了图方便,把 MySQL 的 bind-address 改成了 0.0.0.0,然后在防火墙里放开 3306。理由很简单:本地 Navicat 连接方便。
一开始确实方便,直到有天 CPU 突然升高,数据库里多了一堆奇怪连接。他查日志才发现,3306 端口早就被扫到了。密码虽然没被撞开,但已经被持续爆破了好几天。
Redis 更吓人。Redis 没密码、直接暴露公网,基本就是等着被扫。网上那些被写计划任务、被挖矿、被清库的事故,很多都是这么来的。
所以这篇只讲一个原则:数据库不是网站,不要为了远程连接方便就直接暴露到公网。
常见数据库端口包括:
- MySQL / MariaDB:3306
- PostgreSQL:5432
- Redis:6379
- MongoDB:27017
- Elasticsearch:9200
这些端口如果暴露在公网,很快就会被扫描。不是“可能有人扫”,而是基本一定会有人扫。
正确思路是:
- 应用和数据库在同一台 VPS:数据库监听本地
127.0.0.1 - 应用和数据库在同一内网:只允许私网 IP 访问
- 本地电脑临时管理:用 SSH 隧道
- 多人长期管理:用 VPN 或堡垒机
- 必须公网访问:只允许固定 IP 白名单,并启用强密码和 TLS
不要把“能连上”当成配置成功。数据库远程访问要先问:谁能连、从哪里连、有没有加密、出事怎么止血。
很多教程会告诉你:把 MySQL 配置里的 bind-address 从 127.0.0.1 改成 0.0.0.0,然后放行 3306,就能远程连接。
技术上没错,安全上很危险。
0.0.0.0 的意思是监听所有网卡。如果防火墙也放开了,那任何公网 IP 都可以尝试连接这个数据库端口。
查监听可以用:
ss -lntp | grep -E '3306|5432|6379|27017|9200'
如果你看到:
0.0.0.0:3306
0.0.0.0:6379
就要警惕。除非你非常确定防火墙只允许可信 IP,否则这就是公网暴露。
更安全的默认值是:
127.0.0.1:3306
127.0.0.1:5432
127.0.0.1:6379
应用和数据库在同一台 VPS 上时,监听本地就够了。Nginx、PHP、Node、Python 应用都可以从本机连接,不需要数据库对公网开放。
如果你只是想在本地电脑用 Navicat、DataGrip、TablePlus 管理数据库,最简单安全的方式是 SSH 隧道。
比如 MySQL 在 VPS 本机 127.0.0.1:3306,你本地执行:
ssh -L 3307:127.0.0.1:3306 root@你的服务器IP
然后本地数据库工具连接:
127.0.0.1:3307
数据实际走 SSH 加密通道,数据库端口没有暴露公网。
PostgreSQL 类似:
ssh -L 5433:127.0.0.1:5432 root@你的服务器IP
Redis 也可以:
ssh -L 6380:127.0.0.1:6379 root@你的服务器IP
这招适合个人管理、临时排查、偶尔改数据。缺点是隧道断了就连不上,但这反而是好事:不用的时候端口自然关闭。
如果团队里多人都要访问数据库,不建议每个人都直接连公网数据库端口。
更稳的做法是:
- WireGuard / Tailscale / ZeroTier 组一个私有网络
- 数据库只监听 VPN 内网地址
- 只允许 VPN 网段访问数据库端口
- 每个人有自己的 VPN 身份和权限
比如数据库服务器有一个 WireGuard 内网 IP:
10.8.0.2
应用服务器或开发电脑通过 VPN 访问:
10.8.0.2:3306
公网安全组和系统防火墙都不开放 3306。外面扫不到数据库端口,风险小很多。
如果你用的是同一云厂商的多台 VPS,也可以用私有网络/VPC。数据库端口只允许内网 IP,不对公网开放。
有些场景确实需要公网访问,比如第三方系统固定 IP 拉数据,或者某个办公出口固定。
这种情况下,不要放 0.0.0.0/0,只允许固定来源 IP。
UFW 示例:
ufw allow from 你的办公公网IP to any port 3306 proto tcp
ufw deny 3306/tcp
ufw status numbered
iptables 思路类似:先允许可信 IP,再拒绝其他来源。
云安全组里也一样:来源写你的固定 IP,不要写 Anywhere。
同时还要做:
- 强密码,不要弱口令
- 禁止 root 远程登录数据库
- 给业务单独建最小权限账号
- 开启 TLS/SSL(尤其跨公网)
- 定期看登录失败日志
- 备份必须可恢复
白名单不是万能,但比全网开放强太多。
Redis 是重灾区。
很多人以为 Redis 只是缓存,被删了再生成就行。但 Redis 一旦暴露,风险不只是数据丢失,还可能被写入恶意任务、利用主从复制写文件、做挖矿跳板。
Redis 至少要做到:
bind 127.0.0.1
protected-mode yes
requirepass 一个足够强的密码
如果要给应用远程访问,优先走内网或 VPN,不要直接公网开 6379。
检查 Redis 是否监听公网:
ss -lntp | grep 6379
如果看到 0.0.0.0:6379,先别犹豫,立刻收回到本地或内网。
如果你发现数据库端口已经公开了一段时间,不要只把端口关掉就完事。
建议按顺序做:
- 立刻在防火墙/安全组关闭公网访问
- 保存日志,不要马上清空
- 检查数据库用户和权限
- 修改所有数据库密码
- 检查是否有陌生账号、陌生库、陌生表
- 检查系统计划任务、SSH key、可疑进程
- 从可信备份对比关键数据
- 如果 Redis/MongoDB 曾裸奔,按入侵事件处理
MySQL 可以看用户:
SELECT user, host FROM mysql.user;
PostgreSQL 看角色:
\du
Redis 则要检查配置、数据、计划任务和系统层面。Redis 裸奔后的影响可能不止 Redis 自己。
在 VPS 上查监听:
ss -lntp | grep -E '3306|5432|6379|27017|9200'
在本地电脑查端口是否能连:
nmap -Pn -p 3306,5432,6379,27017,9200 你的服务器IP
如果本地电脑能扫到这些端口 open,而你又没有做白名单,那基本就是公网可访问。
再查防火墙:
ufw status verbose
iptables -L -n -v
云厂商控制台也要看一遍安全组。很多人只关了系统防火墙,忘了云防火墙;也有人云安全组收紧了,但系统里服务还在监听公网。两边都要查。
给一张简单表:
| 场景 | 推荐方案 |
|---|---|
| 本机应用连本机数据库 | 监听 127.0.0.1 |
| 本地电脑偶尔管理 | SSH 隧道 |
| 团队长期管理 | WireGuard / Tailscale / ZeroTier |
| 多台 VPS 内部通信 | 私有网络 / VPC |
| 第三方固定 IP 接入 | 公网白名单 + TLS + 最小权限 |
| Redis 缓存 | 本机或内网,尽量不公网 |
| 临时排查 | 临时白名单,用完立刻删 |
如果你不知道选哪个,默认选 SSH 隧道。简单、安全、够用。
新 VPS 部署数据库后,我会这样检查:
- MySQL/PostgreSQL/Redis 是否只监听本地或内网
- 防火墙是否没有全网开放 3306/5432/6379
- 云安全组是否没有 Anywhere 入站规则
- 是否禁止数据库 root/admin 远程登录
- 是否为业务创建最小权限账号
- 是否有强密码或密钥认证
- 是否需要 TLS/SSL
- 是否配置了备份和恢复演练
- 是否知道日志在哪里看
- 是否记录了谁可以访问数据库
数据库远程访问这件事,方便和安全经常冲突。我的建议是:能不公网就不公网,能走隧道就走隧道,能走内网就走内网。
真正需要公开访问时,也不要把数据库当普通 Web 服务暴露。Web 端口可以面向用户,数据库端口应该只面向你信任的机器和人。
