PostgreSQL 开启 SSL/TLS 完整配置教程

适用版本

PostgreSQL 9.6 ~ 16 全版本通用(主流 12/13/14/15/16 最优),本教程包含「自建自签名证书(90% 场景首选)」+「CA 签发合规证书」+「服务端强制 SSL」+「客户端加密连接」+「验证生效」+「常见排错」,一步到位,无冗余步骤。
 
核心前提:PostgreSQL 原生内置 SSL/TLS 支持,无需额外安装任何插件,所有操作均为原生配置,安全可靠。

 

一、核心概念说明

  1. SSL 和 TLS 关系:SSL 是 TLS 的前身,PostgreSQL 中配置项写的是 ssl,但实际启用的是 TLS 1.2/TLS 1.3(高版本 PG 默认),两者是同一个安全加密协议的不同版本,下文统一叫 SSL/TLS。
  2. 证书文件作用:开启 SSL 必须有密钥 + 证书文件,证书用于身份验证,密钥用于通信加密,缺一不可。
  3. 两种证书方案(按需选择):
     
    ✅ 方案 A:自建「自签名证书」 → 推荐,测试环境 / 生产内网环境 首选,零成本、配置简单,加密效果和 CA 证书一致,唯一缺点是客户端连接时会提示证书未被信任(可忽略 / 配置信任)。
     
    ✅ 方案 B:CA 机构签发的合规证书 → 适合公网对外提供服务的生产环境(如云数据库、公网业务连接),合规性强,客户端无证书警告,需要购买 / 申请 CA 证书(如 Let's Encrypt 免费 CA)。
 

 

二、方案 A:自建自签名证书(✅ 优先选择,90% 场景够用)

 

2.1 证书生成(核心步骤,两种方式任选其一)

✔ 方式 1:使用 PostgreSQL 自带脚本(最简单,推荐新手)

 
PostgreSQL 安装后自带了生成自签名证书的脚本 pg_ssl_create_cert.sh,一键生成所有需要的证书,零命令书写错误风险,证书自动生成到 PostgreSQL 的数据目录($PGDATA)。
# 1. 切换到postgres用户(必须,证书权限要求严格,禁止root操作)
su - postgres

# 2. 一键生成SSL证书(自动生成到 $PGDATA 目录)
/usr/pgsql-14/bin/pg_ssl_create_cert.sh  # 版本替换为你的PG版本,如12/15/16
# 若不知道路径,执行 find / -name pg_ssl_create_cert.sh 查找
 
 

✔ 方式 2:使用 openssl 手动生成(灵活,推荐运维人员)

 
如果系统没有自带脚本,用openssl命令手动生成,证书同样放在 $PGDATA 目录,所有操作必须在 postgres 用户下执行:
 
# 切换postgres用户
su - postgres
# 进入PG数据目录(核心!证书必须放这里)
cd $PGDATA

# 1. 生成服务端私钥(server.key),权限必须600,postgres用户属主
openssl genrsa -out server.key 2048
chmod 0600 server.key

# 2. 生成证书签名请求(CSR)
openssl req -new -key server.key -out server.csr -subj "/CN=你的PG服务器IP/OU=DBA/O=company/C=CN"

# 3. 生成自签名证书(server.crt),有效期10年(3650天),避免频繁过期
openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt

# 4. 生成根证书(可选,客户端验证用)
openssl req -new -x509 -days 3650 -nodes -text -out root.crt -keyout root.key -subj "/CN=root"
chmod 0600 root.key
 
 

2.2 证书文件检查(必做,踩坑点)

 
生成完成后,$PGDATA 目录下会出现以下核心证书文件,权限 + 属主错误会导致 PG 启动失败 / SSL 不生效,是最常见的坑:
# 检查证书文件及权限(必须满足如下)
ls -l $PGDATA/server.*
# 正确权限示例:
# -rw-------. 1 postgres postgres  1113  1月 14 10:00 server.crt
# -rw-------. 1 postgres postgres  1675  1月 14 10:00 server.key
 
 
✅ 要求:
 
  1. 证书文件属主 / 属组必须是 postgres:postgres
  2. server.key 权限必须是 0600(严格只读,禁止其他用户访问);
  3. server.crt 权限可以是 0644
 

 

三、服务端核心配置(重中之重,2 个配置文件)

 
开启 SSL 需要修改 PG 的 2 个核心配置文件,均在 $PGDATA 目录下,修改后必须重启 PG 服务才会生效,配置项均为生产最优配置,可直接复制粘贴。
 

3.1 修改 postgresql.conf 开启 SSL 核心配置

# 编辑配置文件
vi $PGDATA/postgresql.conf
 
 
将以下配置项修改 / 新增,注释的取消注释,原值替换:
 
# 1. 核心开关:开启SSL/TLS,必填!
ssl = on

# 2. 监听地址:允许远程连接,* 表示监听所有网卡,必填(本地连接可写localhost)
listen_addresses = '*'

# 3. SSL证书文件路径(默认就是$PGDATA,无需修改,写绝对路径更稳妥)
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
ssl_root_cert_file = 'root.crt'  # 可选,CA证书验证用

# 4. 安全配置:只启用高安全的TLS协议版本,禁用老旧的SSLv2/SSLv3
ssl_min_protocol_version = 'TLSv1.2'
ssl_max_protocol_version = 'TLSv1.3'

# 5. 加密套件:只使用高强度加密算法,增强安全性
ssl_ciphers = 'HIGH:!aNULL:!MD5:!3DES'
ssl_prefer_server_ciphers = on

# 6. 其他安全增强(可选)
ssl_ecdh_curve = 'prime256v1'
ssl_session_cache = 'shared:SSL:1000'
 
 

3.2 修改 pg_hba.conf 配置 SSL 访问策略(核心!控制加密 / 明文)

 
pg_hba.conf 是 PG 的访问控制列表,决定「谁能通过什么方式连接数据库」,这一步是 SSL 是否强制生效的关键,90% 的用户 SSL 配置后不生效都是因为这个文件配置错误!
 

✅ 核心规则

  • host :允许明文连接 + SSL 连接(不强制加密,风险高)
  • hostssl:仅允许 SSL/TLS 加密连接(推荐生产环境,强制加密,核心!)
  • hostnossl:仅允许明文连接(禁用)
 

推荐配置(生产环境,直接替换原有规则)

# 编辑配置文件
vi $PGDATA/pg_hba.conf
 
 
添加 / 修改如下规则,删除原有所有 host 开头的明文规则,只保留 hostssl 规则:
 
# 允许 所有IP 用SSL加密连接 所有数据库 所有用户,密码认证(生产常用)
hostssl  all  all  0.0.0.0/0  scram-sha-256
# 若你的PG版本较低,无scram-sha-256,替换为 md5
# hostssl  all  all  0.0.0.0/0  md5

# 允许本地unix socket连接(本地免密,不影响)
local   all             all                                     peer
 
关键:配置 hostssl 后,客户端必须通过 SSL 加密连接,明文连接会被直接拒绝,彻底杜绝明文传输的安全风险。

 

四、重启 PostgreSQL 服务使配置生效

 
根据你的操作系统,执行对应的重启命令,必须 postgres 用户或 root 用户执行:
 
# ========== CentOS7/RHEL7/8/9 / RockyLinux  ==========
systemctl restart postgresql-14  # 版本替换为你的PG版本
systemctl enable postgresql-14   # 开机自启(可选)

# ========== Debian/Ubuntu  ==========
systemctl restart postgresql
systemctl enable postgresql

# ========== 通用方式(任意系统) ==========
pg_ctl restart -D $PGDATA -m fast
 
 

检查服务状态

systemctl status postgresql-14
 
 
✅ 正常状态:active (running),无报错即配置生效;如果启动失败,查看日志 tail -f $PGDATA/postgresql-*.log 排查证书权限 / 配置错误。
 

 

五、验证 SSL/TLS 是否成功启用(3 种方法,从简到繁)

 
配置完成后,务必验证 SSL 是否生效,避免配置成功但实际是明文连接,推荐按顺序执行,任选其一即可确认。
 

✔ 方法 1:本地 psql 连接,查看连接信息(最简单,推荐)

 
# 切换postgres用户,本地连接数据库
su - postgres
psql -U postgres -d postgres

# 执行命令查看SSL状态
postgres=# \conninfo
 
 
✅ 成功开启 SSL 的返回结果(包含 SSL connection 关键字):
 
You are connected to database "postgres" as user "postgres" via socket in "/var/run/postgresql" at port "5432".
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
 
出现 SSL connection 就代表当前连接是加密的,协议 / 加密套件会根据你的配置显示。

✔ 方法 2:执行 SQL 查询系统视图(精准,运维常用)

 
连接 PG 后执行以下 SQL,可查看所有当前连接的 SSL 状态,适合批量检查:
 
SELECT datname, usename, ssl, version, cipher 
FROM pg_stat_ssl s JOIN pg_stat_activity a ON s.pid = a.pid;
 
 
✅ 结果说明:
 
  • ssl 列值为 t → 加密连接;f → 明文连接;
  • version 列显示 TLS 协议版本(如 TLSv1.3);
  • cipher 列显示加密套件。
 

✔ 方法 3:查看 PG 进程监听(辅助验证)

 
netstat -tulnp | grep postgres
 
 
✅ 结果:PG 的 5432 端口正常监听,无异常即可。
 

 

六、客户端通过 SSL/TLS 连接 PostgreSQL(最全场景)

 
服务端开启 SSL 后,客户端连接分为「本地连接」「远程 psql 连接」「应用程序连接」,所有客户端连接都支持 SSL,核心是 sslmode 参数,这是客户端的核心配置,必须掌握!
 

✅ 核心:客户端 sslmode 6 种取值(优先级从低到高,安全级别递增)

 
PostgreSQL 客户端的 sslmode 决定了「是否使用 SSL 连接、是否验证服务端证书」,生产环境务必使用高安全级别,所有场景通用,解释如下:
1. disable    → 禁用SSL,强制明文连接(禁止使用!)
2. allow      → 优先明文,失败则尝试SSL(不推荐)
3. prefer     → 优先SSL,失败则明文(测试环境可用)
4. require    → 强制SSL加密连接,不验证服务端证书真伪(✅ 生产内网首选,90%场景用这个)
5. verify-ca  → 强制SSL,验证服务端证书是否由可信CA签发(自建证书需配置root.crt)
6. verify-full→ 强制SSL,验证证书+验证证书中的主机名/IP和实际连接一致(✅ 公网生产首选,最高安全)
 
 

6.1 远程 psql 客户端连接(带 SSL)

 
# 方式1:生产内网最优 → sslmode=require 强制加密,无需证书
psql -h 你的PG服务器IP -p 5432 -U postgres -d postgres -sslmode=require

# 方式2:公网高安全 → sslmode=verify-full,指定根证书
psql -h 你的PG服务器IP -p 5432 -U postgres -d postgres -sslmode=verify-full -sslrootcert=/tmp/root.crt
 
 

6.2 配置 pg_hba.conf 免证书连接(推荐)

 
如果是自建自签名证书,不想每次客户端连接都带证书,只需在服务端 pg_hba.conf 中配置 hostssl 即可,客户端用 sslmode=require 就能直接加密连接,无需任何证书文件,最简单高效。
 

6.3 主流应用程序 SSL 连接配置(生产必备,直接复制)

 

✔ Java / JDBC 连接(SpringBoot/Mybatis)

jdbc:postgresql://192.168.1.100:5432/testdb?user=postgres&password=123456&sslmode=require
 
 

✔ Python / psycopg2

 
import psycopg2
conn = psycopg2.connect(
    host="192.168.1.100",
    port=5432,
    dbname="testdb",
    user="postgres",
    password="123456",
    sslmode="require"
)
 
 

✔ PHP / PDO

 
$dbh = new PDO("pgsql:host=192.168.1.100;port=5432;dbname=testdb;sslmode=require", "postgres", "123456");
 
 

✔ Navicat/DBeaver 图形化工具

 
连接配置中,在「SSL」选项卡:
 
  • 勾选「使用 SSL」;
  • SSL 模式选择「Require」;
  • 无需上传证书,直接测试连接即可。
 

 

七、方案 B:生产合规 - 配置 CA 签发的正式证书(公网场景)

 
如果你的 PostgreSQL 需要对公网提供服务(如云服务器、外网业务),推荐使用正规 CA 机构签发的证书(如 Let's Encrypt 免费证书、阿里云 / 腾讯云付费证书),配置方式和自建证书几乎一致,仅需替换证书文件即可:
 
  1. 将 CA 签发的 server.crt(服务端证书)、server.key(服务端私钥)、ca.crt(CA 根证书)放到 $PGDATA 目录;
  2. 确保权限是 postgres:postgresserver.key 权限 0600;
  3. 修改 postgresql.conf 中的 ssl_root_cert_file = 'ca.crt'
  4. 客户端连接时使用 sslmode=verify-full,即可完成证书的双向验证,彻底杜绝中间人攻击。
 

 

八、常见问题排查(✅ 99% 的坑都在这里,必看)

 

问题 1:PG 重启失败,日志报错 could not load private key file "server.key": Permission denied

 
✅ 原因:证书权限错误,解决方案:
 
chown -R postgres:postgres $PGDATA/server.*
chmod 0600 $PGDATA/server.key
chmod 0644 $PGDATA/server.crt
 
 

问题 2:客户端连接报错 FATAL: no pg_hba.conf entry for host "xxx.xxx.xxx.xxx", user "postgres", database "postgres", SSL off

 
✅ 原因:服务端 pg_hba.conf 中只有 hostssl 规则,客户端用了明文连接(sslmode=disable);
 
✅ 解决方案:客户端连接时添加 sslmode=require 即可。
 

问题 3:客户端连接成功,但执行 \conninfo 显示无 SSL connection

 
✅ 原因:pg_hba.conf 中配置的是 host 规则,不是 hostssl,PG 优先走明文连接;
 
✅ 解决方案:删除 host 规则,只保留 hostssl 规则,重启 PG。
 

问题 4:自建证书,客户端连接报错 SSL certificate verification failed

 
✅ 原因:客户端开启了 verify-ca/verify-full,但未配置根证书;
 
✅ 解决方案:客户端连接时指定根证书 sslrootcert=root.crt,或改用 sslmode=require
 

posted on 2026-01-14 09:22  阿陶学长  阅读(77)  评论(0)    收藏  举报