配置文件位置与加载
PostgreSQL 的配置分散在 postgresql.conf、pg_hba.conf、pg_ident.conf 三个文件中,而不同安装方式下它们的位置完全不同——这是初学者最容易踩的坑。本节讲清三者的职责、位置差异,以及 include 机制与「只加载配置 vs 重启」的对应关系。
前置知识
阅读本节前,建议先了解:多版本并存(pg_lsclusters)
基础概念
postgresql.conf:服务端主配置,控制内存、连接数、日志、复制等所有运行参数pg_hba.conf:主机认证(Host-Based Authentication)配置,决定「谁、从哪、用什么方式」能连上数据库pg_ident.conf:用户身份映射(Identity Mapping),把操作系统用户名映射为数据库用户名,配合peer/gss/cert认证使用- 数据目录(Data Directory):默认包含上述三个文件;
initdb会在其中生成它们 - 配置目录(Config Directory):Debian / Ubuntu 下独立的
/etc/postgresql/<版本>/<名称>/,与数据目录分离 - 只加载配置(Reload):重新读取配置文件,不重启进程,等价于发送
SIGHUP。也叫「重载」 - 重启(Restart):终止并重新启动服务,会中断所有连接
- 参数上下文(Parameter Context):决定参数生效方式,取值
internal/postmaster/sighup/user/superuser/backend - 附加配置(Include):通过
include/include_dir/include_if_exists把配置拆分成多个文件
| 文件 | 主要职责 | 修改后生效方式 | 是否可省略 |
|---|---|---|---|
postgresql.conf | 运行参数(内存、日志、复制等) | 视参数而定,reload 或 restart | 不可,必需 |
pg_hba.conf | 客户端认证规则 | reload | 可以,缺省时只允许本地 |
pg_ident.conf | 系统用户到数据库用户的映射 | reload | 可以,仅在用到映射时需要 |
postgresql.auto.conf | ALTER SYSTEM 写入的配置 | 自动 reload | 自动生成 |
conf.d/*.conf | 拆分出来的附加配置 | reload 或 restart | 可以 |
版本说明
PostgreSQL 12 起,postgresql.conf 与 pg_hba.conf 支持 include_dir 方式加载目录下的片段。18 中 ALTER SYSTEM 的行为更加明确:写入 postgresql.auto.conf,其优先级高于 postgresql.conf,且手工编辑该文件会被下一次 ALTER SYSTEM 覆盖。
语法与用法
定位当前配置文件位置
这是排查问题的第一步——不要假设配置文件在哪。
# 方式 1:通过 psql 询问服务端(最权威,显示实际加载的路径)
sudo -u postgres psql -c "SHOW config_file;" -c "SHOW hba_file;" -c "SHOW ident_file;" config_file
------------------------------------------
/etc/postgresql/18/main/postgresql.conf
(1 row)
hba_file
----------------------------------------
/etc/postgresql/18/main/pg_hba.conf
(1 row)
ident_file
-----------------------------------------
/etc/postgresql/18/main/pg_ident.conf
(1 row)# 方式 2:查看进程启动参数(能看到 -D 指定的数据目录)
ps -ef | grep '[p]ostgres'postgres 1147 1 0 09:12 ? 00:00:01 /usr/lib/postgresql/18/bin/postgres -D /var/lib/postgresql/18/main -c config_file=/etc/postgresql/18/main/postgresql.conf# 方式 3:直接看数据目录(RPM / 源码 / Docker 安装方式下配置就在此处)
ls -l "$PGDATA"/postgresql.conf "$PGDATA"/pg_hba.conf "$PGDATA"/pg_ident.conf-rw------- 1 postgres postgres 28734 Sep 21 09:05 /var/lib/pgsql/18/data/pg_hba.conf
-rw------- 1 postgres postgres 2693 Sep 21 09:05 /var/lib/pgsql/18/data/pg_ident.conf
-rw------- 1 postgres postgres 28519 Sep 21 09:05 /var/lib/pgsql/18/data/postgresql.conf| 安装方式 | postgresql.conf 位置 | 数据目录 |
|---|---|---|
| Debian / Ubuntu(APT) | /etc/postgresql/18/main/ | /var/lib/postgresql/18/main/ |
| RHEL / Rocky(YUM / DNF) | /var/lib/pgsql/18/data/ | /var/lib/pgsql/18/data/ |
| macOS(Homebrew) | /opt/homebrew/var/postgresql@18/ | 同左 |
| Docker 官方镜像 | /var/lib/postgresql/data/(或 18 的版本子目录) | 同左 |
| 源码编译 | $PGDATA(自行指定,如 /var/lib/pgsql/18/data) | 同左 |
Debian 系特有的陷阱
Debian / Ubuntu 下,数据目录里也有一份 postgresql.conf,但那只是 initdb 生成的模板,服务实际读取的是 /etc/postgresql/18/main/postgresql.conf(由 systemd 的 -c config_file=... 指定)。直接改数据目录里那份不会生效,这是极高频的踩坑点。
参数上下文与生效方式
# 查看某个参数的上下文(枚举值),据此判断能否 reload
sudo -u postgres psql -c "SELECT name, context, vartype, boot_val, setting
FROM pg_settings WHERE name IN
('shared_buffers','max_connections','work_mem','log_min_duration_statement','port');" name | context | vartype | boot_val | setting
----------------------------+------------+---------+----------+---------
log_min_duration_statement | superuser | integer | -1 | -1
max_connections | postmaster | integer | 100 | 100
port | postmaster | integer | 5432 | 5433
shared_buffers | postmaster | integer | 16384 | 16384
work_mem | user | integer | 4096 | 4096
(5 rows)context 取值 | 生效方式 | 典型参数 | 说明 |
|---|---|---|---|
internal | 只能改源码重编译 | block_size、wal_block_size | 只读 |
postmaster | 必须重启 | shared_buffers、max_connections、port | 涉及进程启动期资源 |
sighup | reload 即可 | log_destination、archive_mode | 重读配置生效 |
superuser | 会话内 SET 或 reload | log_min_duration_statement | 超级用户可动态改 |
user | 会话内 SET | work_mem、search_path | 普通用户也可改 |
backend | 新连接生效 | statement_timeout(全局设定时) | 仅影响新会话 |
# 修改配置后判断该用哪种方式:若含 postmaster 上下文参数就只能重启
sudo -u postgres psql -c "SELECT name FROM pg_settings
WHERE context = 'postmaster' AND setting IS DISTINCT FROM reset_val;" name
---------------
max_connections
shared_buffers
(2 rows)include 与配置拆分
# /etc/postgresql/18/main/postgresql.conf(节选)
# 主配置只保留框架与最核心的设置,其余按用途拆分
listen_addresses = 'localhost'
port = 5432
# 引入单个文件(若文件不存在则启动报错)
#include 'custom.conf'
# 引入目录下所有以 .conf 结尾的文件,按文件名排序加载
# 后加载的会覆盖先加载的同名参数
include_dir = 'conf.d'
# 文件不存在也不报错,适合可选的本地覆盖
#include_if_exists = 'local.conf'# 查看 include_dir 实际加载了哪些文件
ls -l /etc/postgresql/18/main/conf.d/total 16
-rw-r--r-- 1 postgres postgres 412 Sep 21 09:20 10-tuning.conf
-rw-r--r-- 1 postgres postgres 305 Sep 21 09:20 20-logging.conf
-rw-r--r-- 1 postgres postgres 198 Sep 21 09:20 30-replication.conf# /etc/postgresql/18/main/conf.d/10-tuning.conf
# 编号前缀决定加载顺序,便于人为控制覆盖关系
shared_buffers = 4GB
effective_cache_size = 12GB
work_mem = 16MB
maintenance_work_mem = 512MB
wal_buffers = 16MB
max_connections = 200# /etc/postgresql/18/main/conf.d/20-logging.conf
logging_collector = on
log_destination = 'stderr'
log_directory = 'log'
log_min_duration_statement = 500
log_line_prefix = '%m [%p] %q%u@%d '| 指令 | 参数类型 | 行为 | 使用建议 |
|---|---|---|---|
include = 'file' | 字符串 | 加载单个文件,不存在则启动失败 | 引入必需的定制片段 |
include_dir = 'dir' | 字符串 | 加载目录内所有 .conf,不存在则启动失败 | 按用途拆分配置 |
include_if_exists = 'file' | 字符串 | 文件不存在则静默跳过 | 可选的本地覆盖 |
include_if_exists_dir = 'dir' | 字符串 | 目录不存在则静默跳过 | 可选的目录覆盖 |
拆分配置的三个好处
一是可审计:调优参数与日志参数分文件,review 时一目了然;二是可覆盖:用编号控制顺序,后加载覆盖前者,便于分层管理;三是可打包:conf.d/ 可以被配置管理工具整体下发,不污染主配置。
详细说明
pg_hba.conf 的结构
pg_hba.conf 每行一条规则,自上而下匹配,命中第一条即停止。这个特性是绝大多数认证问题的根源。
# /etc/postgresql/18/main/pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
# 本地 Unix Socket 连接:peer 表示用操作系统用户名做认证
local all postgres peer
local all all peer
# 本机回环的 TCP 连接
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
# 应用服务器网段:只允许 app 用户访问 appdb
host appdb app 10.0.1.0/24 scram-sha-256
# 复制连接:只允许特定账号从备库地址连接,且只允许 replication 库
host replication repl 10.0.2.11/32 scram-sha-256
# 拒绝其他所有来源(显式兜底,避免出现「意外放行」)
host all all 0.0.0.0/0 reject| 字段 | 取值 | 说明 |
|---|---|---|
TYPE | local / host / hostssl / hostnossl | 连接通道类型 |
DATABASE | all / 数据库名 / 逗号分隔列表 / @file | 允许访问的库 |
USER | all / 角色名 / 列表 / +角色组 / @file | 允许连接的账号 |
ADDRESS | CIDR 或 IP 掩码;local 行留空 | 来源地址 |
METHOD | trust / reject / scram-sha-256 / md5 / peer / ident / cert / pam / ldap / gss | 认证方式 |
OPTIONS(可选) | 键值对 | 传给认证方法的附加参数 |
# 认证方式对比
trust → 无条件放行,任何人无需密码(仅限本地测试)
peer → 用 Unix Socket 对端进程的 OS 用户名比对数据库用户名
scram-sha-256→ 挑战应答,密码不以明文传输,18 的默认推荐
md5 → 已不推荐,质询应答但保护强度不足
cert → 用客户端证书做认证,适合服务间通信
reject → 明确拒绝,用于兜底规则规则顺序决定一切
若把 host all all 0.0.0.0/0 trust 放在文件前面,后面所有更严格的规则都不会生效。修改 pg_hba.conf 后建议用 --dry-run 之外的方式验证:务必用 psql 实际连一次,而不是只看文件内容。
pg_ident.conf 的作用
当使用 peer(本地)或 cert / gss(网络)认证时,可以通过身份映射把「系统身份」转换成「数据库身份」。
# /etc/postgresql/18/main/pg_ident.conf
# MAPNAME SYSTEM-USERNAME PG-USERNAME
# 把操作系统的 deploy 用户映射为数据库的 app_user
deploy_map deploy app_user
# 允许 dev1、dev2 两个系统用户都映射为分析师角色
deploy_map dev1 analyst
deploy_map dev2 analyst
# 正则示例:把 ci-runner-* 这类系统用户统一映射
ci_map /^ci-runner-(.*)$ \1# /etc/postgresql/18/main/pg_hba.conf(配合部分)
# 引用 pg_ident.conf 中定义的映射名,二者必须一致
local all all peer map=deploy_map
host all all 10.0.1.0/24 cert map=ci_map| 配置项 | 出现位置 | 作用 |
|---|---|---|
map=映射名 | pg_hba.conf 的 OPTIONS 字段 | 指定使用哪组映射 |
| 映射名 | 两个文件中都要有 | 作为关联键,拼写必须完全一致 |
| 系统用户名 | pg_ident.conf 第 2 列 | 支持正则、可选 all |
| 数据库用户名 | pg_ident.conf 第 3 列 | 目标角色,支持 \1 反向引用 |
ALTER SYSTEM 与 postgresql.auto.conf
-- 用 SQL 修改参数,无需登录服务器编辑文件
ALTER SYSTEM SET work_mem = '32MB';
ALTER SYSTEM SET log_min_duration_statement = '200ms';
-- 针对特定数据库而非全局
ALTER SYSTEM SET work_mem = '64MB' FOR DATABASE appdb;
ALTER SYSTEM RESET log_min_duration_statement;
ALTER SYSTEM RESET ALL;
-- 让改动生效(若参数可 reload)
SELECT pg_reload_conf();# /var/lib/postgresql/18/main/postgresql.auto.conf
# 本文件由 ALTER SYSTEM 管理,手工编辑的内容会被下次 ALTER SYSTEM 覆盖
work_mem = '32MB'
log_min_duration_statement = '200ms'# 服务端是否允许改配置(ALTER SYSTEM 的前提)
sudo -u postgres psql -c "SHOW config_file;" -c "SHOW data_directory;"
sudo -u postgres psql -c "SELECT name, setting FROM pg_settings
WHERE name IN ('config_file','hba_file','data_directory','allow_system_table_mods');"| 修改方式 | 写入位置 | 优先级 | 适合场景 |
|---|---|---|---|
编辑 postgresql.conf | 主配置 | 最低 | 初始化、批量变更 |
include_dir 片段 | conf.d/ | 高于主配置(后加载) | 按用途拆分、配置管理下发 |
ALTER SYSTEM | postgresql.auto.conf | 最高 | 临时调整、按库/按角色设定 |
SET / pg_reload_conf() | 内存/会话 | 会话级最高 | 单个会话或临时实验 |
为什么「改了配置没生效」
按优先级从低到高检查:一是确认改的是实际加载的配置文件(用 SHOW config_file 确认);二是检查是否有 conf.d/ 或 postgresql.auto.conf 覆盖了你的值;三是判断该参数是否需要重启而非 reload;四是确认是否在错误的数据库/会话里设置了局部值。查 pg_settings 的 source 列最直接:
SELECT name, setting, source, sourcefile, sourceline
FROM pg_settings WHERE name = 'work_mem';配置生效方式对照
# reload:不中断连接
sudo -u postgres psql -c "SELECT pg_reload_conf();"
# 或
sudo systemctl reload postgresql@18-main
# restart:中断连接
sudo systemctl restart postgresql@18-main| 配置项 | 生效方式 | 验证命令 |
|---|---|---|
pg_hba.conf 全部内容 | reload | 重新用 psql 连接 |
pg_ident.conf 全部内容 | reload | 重新用 psql 连接 |
log_line_prefix、log_min_duration_statement | reload | SHOW log_line_prefix |
listen_addresses | restart | ss -lntp |
port | restart | SHOW port |
shared_buffers | restart | SHOW shared_buffers |
max_connections | restart | SHOW max_connections |
wal_level | restart | SHOW wal_level |
work_mem | 新会话或会话内 SET | SET work_mem 后 SHOW |
实战示例
场景一:从零配置一台可被内网访问的实例
# ---------- 步骤 1:确认实际加载的配置文件 ----------
sudo -u postgres psql -tAc "SHOW config_file, hba_file, ident_file;" 2>/dev/null || \
sudo -u postgres psql -c "SHOW config_file;"
CONF=/etc/postgresql/18/main/postgresql.conf
# ---------- 步骤 2:监听内网地址(需重启) ----------
sudo sed -i "s/^#*listen_addresses.*/listen_addresses = 'localhost,192.168.10.20'/" "$CONF"
sudo systemctl restart postgresql@18-main
# ---------- 步骤 3:写认证规则(reload 即可) ----------
sudo tee -a /etc/postgresql/18/main/pg_hba.conf >/dev/null <<'EOF'
# 内网应用网段:仅允许 app 用户访问 appdb(追加在文件末尾,注意前面的规则优先)
host appdb app 192.168.10.0/24 scram-sha-256
EOF
sudo systemctl reload postgresql@18-main
# ---------- 步骤 4:创建业务角色与库 ----------
sudo -u postgres psql <<'SQL'
CREATE ROLE app LOGIN PASSWORD 'Ch4nge_M3_Str0ng';
CREATE DATABASE appdb OWNER app ENCODING 'UTF8';
SQLCREATE ROLE
CREATE DATABASE# ---------- 步骤 5:实际验证(绝不能只改文件就认为完成) ----------
# 本机回环用密码连接
PGPASSWORD='Ch4nge_M3_Str0ng' psql -h 192.168.10.20 -p 5432 -U app -d appdb \
-c "SELECT current_user, current_database(), inet_server_addr();" current_user | current_database | inet_server_addr
--------------+------------------+------------------
app | appdb | 192.168.10.20
(1 row)场景二:用 conf.d 做分层配置管理
# ---------- 步骤 1:确认主配置已开启 include_dir ----------
grep -n "include_dir" /etc/postgresql/18/main/postgresql.conf63:include_dir = 'conf.d'# ---------- 步骤 2:按「机器角色」下发配置片段 ----------
sudo mkdir -p /etc/postgresql/18/main/conf.d
# 服务器规格层:只与内存/CPU 有关
sudo tee /etc/postgresql/18/main/conf.d/10-tuning.conf >/dev/null <<'EOF'
# /etc/postgresql/18/main/conf.d/10-tuning.conf
# 32C / 128G 规格的基础调优,机器规格变化时才需调整本文件
shared_buffers = 32GB
effective_cache_size = 96GB
work_mem = 32MB
maintenance_work_mem = 2GB
max_connections = 500
EOF
# 业务角色层:只与这台机器的职责有关
sudo tee /etc/postgresql/18/main/conf.d/20-logging.conf >/dev/null <<'EOF'
# /etc/postgresql/18/main/conf.d/20-logging.conf
# 日志级别与慢查询阈值:所有实例统一
logging_collector = on
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d.log'
log_min_duration_statement = 500
log_line_prefix = '%m [%p] %q%u@%d/%a '
EOF# ---------- 步骤 3:确认生效结果与参数来源 ----------
sudo systemctl reload postgresql@18-main
sudo -u postgres psql -c "SELECT name, setting, source, sourcefile
FROM pg_settings
WHERE name IN ('shared_buffers','work_mem','log_min_duration_statement')
ORDER BY name;" name | setting | source | sourcefile
----------------------------+---------+------------------+--------------------------------------------
log_min_duration_statement | 500 | configuration file | /etc/postgresql/18/main/conf.d/20-logging.conf
shared_buffers | 4194304 | configuration file | /etc/postgresql/18/main/conf.d/10-tuning.conf
work_mem | 32768 | configuration file | /etc/postgresql/18/main/conf.d/10-tuning.conf
(3 rows)shared_buffers 单位说明
pg_settings.setting 返回的是以「块」(8KB)为单位的原始数字,4194304 块 × 8KB = 32GB。要看人类可读的数值,用 SHOW shared_buffers; 或查 pg_size_pretty(pg_size_bytes(...))。
场景三:临时调整与回滚
-- 通过 ALTER SYSTEM 临时提高慢查询记录阈值
ALTER SYSTEM SET log_min_duration_statement = '100ms';
SELECT pg_reload_conf(); -- reload 生效
-- 验证写入位置与优先级
SELECT name, setting, source FROM pg_settings WHERE name = 'log_min_duration_statement'; name | setting | source
----------------------------+---------+---------------------------
log_min_duration_statement | 100 | configuration file# 查看自动配置文件内容(确认写入成功)
sudo cat /var/lib/postgresql/18/main/postgresql.auto.conf# Do not edit this file manually!
# It will be overwritten by the ALTER SYSTEM command.
log_min_duration_statement = '100ms'-- 排查完成后回滚到 conf.d 里的全局设定
ALTER SYSTEM RESET log_min_duration_statement;
SELECT pg_reload_conf();
-- 再用 source 确认来源已回到 conf.d 文件
SELECT name, setting, source, sourcefile FROM pg_settings
WHERE name = 'log_min_duration_statement'; name | setting | source | sourcefile
----------------------------+---------+--------------------+-----------------------------------------
log_min_duration_statement | 500 | configuration file | /etc/postgresql/18/main/conf.d/20-logging.conf场景四:Docker 环境下修改配置
# 官方镜像中配置与数据同在 PGDATA 下,推荐用 -c 参数覆盖单项而非覆盖整个文件
docker run -d --name pg18 \
-e POSTGRES_PASSWORD='Str0ng_P@ss' \
-p 5432:5432 \
-v pgdata18:/var/lib/postgresql \
postgres:18 \
-c shared_buffers=1GB \
-c max_connections=200 \
-c log_min_duration_statement=500
# 验证已生效的参数
docker exec -u postgres pg18 psql -c "SHOW shared_buffers;" -c "SHOW max_connections;" shared_buffers
----------------
1GB
(1 row)
max_connections
-----------------
200
(1 row)# 需要加入 pg_hba.conf 规则时,用 initdb 专用目录挂载(只在首次初始化时执行)
# 或用宿主机的 pg_hba.conf 覆盖容器内文件后 reload
docker cp ./pg_hba.conf pg18:/var/lib/postgresql/18/docker/pg_hba.conf
docker exec -u postgres pg18 psql -c "SELECT pg_reload_conf();"注意事项
- Debian / Ubuntu 下改数据目录里的
postgresql.conf不会生效,必须改/etc/postgresql/<版本>/<名称>/下的文件 - 改动配置后先确认参数上下文,
postmaster类参数必须重启,靠 reload 永远无效 pg_hba.conf自上而下匹配,第一条命中即生效;过宽的规则放在前面会让后面的安全规则全部失效- 认证方式禁用
trust与md5,生产统一用scram-sha-256;trust仅限本地测试且必须绑定127.0.0.1 pg_ident.conf中的map=名称必须与pg_hba.conf引用的一致,拼写错误会让连接直接失败postgresql.auto.conf由ALTER SYSTEM管理,手工编辑会在下次执行时被覆盖,且其优先级高于postgresql.confinclude/include_dir指定的路径是相对于当前配置文件所在目录,写绝对路径时要注意容器与宿主机路径差异include指定的文件不存在会导致服务启动失败,而include_if_exists不会;拆分配置时注意选择include_dir只加载.conf扩展名的文件,其他后缀会被忽略pg_settings.setting中部分参数返回的是内部单位(如块数),不要直接当字节数理解- Docker 环境下直接覆盖容器内
postgresql.conf会丢失镜像内的必要默认值,优先用-c参数覆盖单项 - 修改配置前先备份原文件;线上改配置应在低峰期进行并准备好回滚命令
最佳实践
- 每次改配置前先用
SHOW config_file确认实际加载路径,消除「改了没生效」的最大来源 - 用
include_dir = 'conf.d'做分层拆分:10-tuning.conf(规格)、20-logging.conf(日志)、30-replication.conf(复制) - 把
conf.d/纳入配置管理与版本控制,用配置管理工具统一下发,避免手工编辑 - 配置变更走「改文件 → reload → 用
pg_settings.source验证 → 记录到变更单」的固定流程 - 需要临时调整时用
ALTER SYSTEM,并在排查结束后立即RESET,防止临时设置沉淀成长期配置 pg_hba.conf末尾加一条reject兜底规则,让「意外放行」变成显式的连接失败- 认证规则按「最小权限 + 最小网段」编写:按库、按用户、按源地址三者同时收窄
- 大改动前用
pg_basebackup或至少备份配置文件,确保可以分钟级回滚 - 用版本化的配置文件模板生成不同环境的配置,避免生产与测试出现难查的配置漂移
- 定期审计
pg_settings中source = default的关键参数(如shared_buffers),确认不是「忘了配置」
下一节
继续学习:日志文件管理