Skip to content

配置文件位置与加载 ​

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.confALTER 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 覆盖。

语法与用法 ​

定位当前配置文件位置 ​

这是排查问题的第一步——不要假设配置文件在哪。

bash
# 方式 1:通过 psql 询问服务端(最权威,显示实际加载的路径)
sudo -u postgres psql -c "SHOW config_file;" -c "SHOW hba_file;" -c "SHOW ident_file;"
text
              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)
bash
# 方式 2:查看进程启动参数(能看到 -D 指定的数据目录)
ps -ef | grep '[p]ostgres'
text
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
bash
# 方式 3:直接看数据目录(RPM / 源码 / Docker 安装方式下配置就在此处)
ls -l "$PGDATA"/postgresql.conf "$PGDATA"/pg_hba.conf "$PGDATA"/pg_ident.conf
text
-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=... 指定)。直接改数据目录里那份不会生效,这是极高频的踩坑点。

参数上下文与生效方式 ​

bash
# 查看某个参数的上下文(枚举值),据此判断能否 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');"
text
            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涉及进程启动期资源
sighupreload 即可log_destination、archive_mode重读配置生效
superuser会话内 SET 或 reloadlog_min_duration_statement超级用户可动态改
user会话内 SETwork_mem、search_path普通用户也可改
backend新连接生效statement_timeout(全局设定时)仅影响新会话
bash
# 修改配置后判断该用哪种方式:若含 postmaster 上下文参数就只能重启
sudo -u postgres psql -c "SELECT name FROM pg_settings
WHERE context = 'postmaster' AND setting IS DISTINCT FROM reset_val;"
text
     name
---------------
 max_connections
 shared_buffers
(2 rows)

include 与配置拆分 ​

ini
# /etc/postgresql/18/main/postgresql.conf(节选)
# 主配置只保留框架与最核心的设置,其余按用途拆分

listen_addresses = 'localhost'
port = 5432

# 引入单个文件(若文件不存在则启动报错)
#include 'custom.conf'

# 引入目录下所有以 .conf 结尾的文件,按文件名排序加载
# 后加载的会覆盖先加载的同名参数
include_dir = 'conf.d'

# 文件不存在也不报错,适合可选的本地覆盖
#include_if_exists = 'local.conf'
bash
# 查看 include_dir 实际加载了哪些文件
ls -l /etc/postgresql/18/main/conf.d/
text
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
ini
# /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
ini
# /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 每行一条规则,自上而下匹配,命中第一条即停止。这个特性是绝大多数认证问题的根源。

ini
# /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
字段取值说明
TYPElocal / host / hostssl / hostnossl连接通道类型
DATABASEall / 数据库名 / 逗号分隔列表 / @file允许访问的库
USERall / 角色名 / 列表 / +角色组 / @file允许连接的账号
ADDRESSCIDR 或 IP 掩码;local 行留空来源地址
METHODtrust / reject / scram-sha-256 / md5 / peer / ident / cert / pam / ldap / gss认证方式
OPTIONS(可选)键值对传给认证方法的附加参数
text
# 认证方式对比
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(网络)认证时,可以通过身份映射把「系统身份」转换成「数据库身份」。

ini
# /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
ini
# /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
-- 用 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();
ini
# /var/lib/postgresql/18/main/postgresql.auto.conf
# 本文件由 ALTER SYSTEM 管理,手工编辑的内容会被下次 ALTER SYSTEM 覆盖
work_mem = '32MB'
log_min_duration_statement = '200ms'
bash
# 服务端是否允许改配置(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 SYSTEMpostgresql.auto.conf最高临时调整、按库/按角色设定
SET / pg_reload_conf()内存/会话会话级最高单个会话或临时实验

为什么「改了配置没生效」

按优先级从低到高检查:一是确认改的是实际加载的配置文件(用 SHOW config_file 确认);二是检查是否有 conf.d/ 或 postgresql.auto.conf 覆盖了你的值;三是判断该参数是否需要重启而非 reload;四是确认是否在错误的数据库/会话里设置了局部值。查 pg_settings 的 source 列最直接:

sql
SELECT name, setting, source, sourcefile, sourceline
FROM pg_settings WHERE name = 'work_mem';

配置生效方式对照 ​

bash
# 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_statementreloadSHOW log_line_prefix
listen_addressesrestartss -lntp
portrestartSHOW port
shared_buffersrestartSHOW shared_buffers
max_connectionsrestartSHOW max_connections
wal_levelrestartSHOW wal_level
work_mem新会话或会话内 SETSET work_mem 后 SHOW

实战示例 ​

场景一:从零配置一台可被内网访问的实例 ​

bash
# ---------- 步骤 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';
SQL
text
CREATE ROLE
CREATE DATABASE
bash
# ---------- 步骤 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();"
text
 current_user | current_database | inet_server_addr
--------------+------------------+------------------
 app          | appdb            | 192.168.10.20
(1 row)

场景二:用 conf.d 做分层配置管理 ​

bash
# ---------- 步骤 1:确认主配置已开启 include_dir ----------
grep -n "include_dir" /etc/postgresql/18/main/postgresql.conf
text
63:include_dir = 'conf.d'
bash
# ---------- 步骤 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
bash
# ---------- 步骤 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;"
text
            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(...))。

场景三:临时调整与回滚 ​

sql
-- 通过 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';
text
            name            | setting |          source
----------------------------+---------+---------------------------
 log_min_duration_statement | 100     | configuration file
bash
# 查看自动配置文件内容(确认写入成功)
sudo cat /var/lib/postgresql/18/main/postgresql.auto.conf
text
# Do not edit this file manually!
# It will be overwritten by the ALTER SYSTEM command.
log_min_duration_statement = '100ms'
sql
-- 排查完成后回滚到 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';
text
 name                       | setting | source             | sourcefile
----------------------------+---------+--------------------+-----------------------------------------
 log_min_duration_statement | 500     | configuration file | /etc/postgresql/18/main/conf.d/20-logging.conf

场景四:Docker 环境下修改配置 ​

bash
# 官方镜像中配置与数据同在 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;"
text
 shared_buffers
----------------
 1GB
(1 row)

 max_connections
-----------------
 200
(1 row)
bash
# 需要加入 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.conf
  • include / 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),确认不是「忘了配置」

下一节

继续学习:日志文件管理

参考链接 ​