刚在一台 Rocky Linux 9 上把 PostgreSQL 15 装完,顺手敲了个psql --version,结果直接弹出来一句bash: psql: command not found。这种反馈我见过太多次了,十个第一次用 yum 装 PostgreSQL 的人里,至少有六七个第一反应是“是不是装失败了”。
其实不是。安装是成功的,服务甚至可能已经起来了,只是 shell 还不知道 PostgreSQL 的命令到底放在哪个目录。今天就把“yum 安装完 PostgreSQL 15 之后的环境变量信息”这件事彻底聊清楚:环境变量是从哪来的、应该配置到哪些文件里、几种配置方式分别适合什么场景,以及我实际踩过的一些坑。这篇文章适合刚接触 PostgreSQL 的新手,也适合玩服务器很多年但偶尔被环境变量绕晕的老手——这类问题看着小,一旦换个发行版、换个数据库版本、换个用户切换方式,细节差异特别大。
1. 先搞清楚:yum 安装的 PostgreSQL 15,文件到底散落在哪里
很多人一上来就配环境变量,却连 PostgreSQL 15 装了哪些目录都不知道,这样配出来的 PATH 很容易出错。所以我建议先花两分钟把安装清单摸清楚。
1.1 二进制目录:/usr/pgsql-15/bin
从 PostgreSQL 官方仓库(PGDG)用 yum/dnf 安装 PostgreSQL 15 时,所有用户侧的命令行工具都会被放到/usr/pgsql-15/bin目录下。这个路径自带版本号,不是/usr/bin,也不是/usr/local/bin。
你可以用下面这串命令验证:
rpm -qa | grep postgresql | sort rpm -ql postgresql15-server | grep -E 'bin/'输出里会出现类似这样的路径:
/usr/pgsql-15/bin/postgres /usr/pgsql-15/bin/initdb /usr/pgsql-15/bin/pg_ctl /usr/pgsql-15/bin/pg_config /usr/pgsql-15/bin/psql需要注意,/usr/pgsql-15/bin里的程序不止这些,还有pg_dump、pg_restore、createdb、vacuumdb等一整套工具。这个目录之所以带版本号,是为了方便同一台机器上同时安装 PostgreSQL 14、15、16 等多个大版本而不冲突。你可以把不同版本的命令分别放在各自目录里。
1.2 数据目录:/var/lib/pgsql/15/data
二进制的兄弟目录是数据目录,也就是PGDATA,默认在/var/lib/pgsql/15/data。postgresql.conf、pg_hba.conf、pg_ident.conf这三个最核心的配置文件,还有PG_VERSION、base/、global/等子目录,全都在这里。
这里有个很容易混淆的点:二进制目录里没有数据库配置文件,数据目录里也没有可执行文件。很多人发现改了postgresql.conf没生效,就是因为改错了目录,改到了一个自己新建的同名文件里。
1.3 系统用户、服务单元和日志位置
通过 yum 安装postgresql15-server时,会自动创建一个名为postgres的系统用户和一个名为postgresql-15的 systemd 服务单元。系统用户的家目录是/var/lib/pgsql,默认 shell 是 bash,但它不是一个“可以随便登录交互式终端”的普通账号,通常只用来跑 PostgreSQL 进程和维护操作。
服务单元的名字很容易记错,不是postgresql,也不是postgresql-15.service的简化版。正确操作是:
systemctl enable --now postgresql-15 systemctl status postgresql-15如果需要初始化数据库集群,一般这么执行:
/usr/pgsql-15/bin/postgresql-15-setup initdb这段命令的本质就是调用initdb去生成/var/lib/pgsql/15/data。初始化完成之前,数据目录是不存在的,很多新手直接启动服务报错,原因就在这里。
1.4 配置文件不一定要到数据目录找
虽然配置文件默认都在数据目录,但有些运维脚本喜欢把postgresql.conf单独拿出来维护,比如放到/etc/postgresql/15/。如果你看到别人的文章里说“配置文件在/etc/postgresql/15/”,不要急着照抄,先确认一下自己的发行版和安装方式。官方 RPM 包的默认行为是配置文件和数据文件放在一起,其他发行版可能不同。遇到问题时,推荐用一条命令确定真实路径:
sudo -u postgres /usr/pgsql-15/bin/psql -t -c "SHOW config_file;"这个习惯能省掉很多弯路。
2. 环境变量到底要配什么,每个变量的作用是啥
搞清楚目录后,再说环境变量就有底气了。下面几个变量是 PostgreSQL 日常使用中最常见的,我一个个解释。
2.1 PATH:为什么 shell 找不到 psql
psql: command not found的原因说白了就是 PATH 里没有/usr/pgsql-15/bin。PATH 是 shell 用来找命令的“目录列表”,当你输入psql时,shell 会按顺序在每个目录里找有没有叫psql的可执行文件。没有,就报 command not found。
当前会话里可以临时验证:
echo "$PATH"输出结果里大概率没有/usr/pgsql-15/bin。你还可以用下面命令看 shell 到底在找什么:
command -v psql type psql这两个命令都会告诉你:找不到。但它们和“服务起没起来”没有关系。
2.2 PGDATA:运维命令的默认数据目录
很多命令行工具和运维脚本都支持通过PGDATA环境变量指定数据目录。比如pg_ctl、pg_controldata,如果不加-D参数,就会尝试从PGDATA读取。设置了它以后,日常操作会方便不少:
export PGDATA=/var/lib/pgsql/15/data但这里要强调一点:systemd 启动 PostgreSQL 服务的时候,完全不看你手动配置的PGDATA。服务单元文件里已经写死了启动命令和数据目录,比如:
ExecStart=/usr/pgsql-15/bin/postmaster -D /var/lib/pgsql/15/data如果你在/etc/profile.d里配了PGDATA,然后一整天都不生效,也不要慌,这是预期行为——环境变量是给人用的,不是给服务用的。
2.3 LD_LIBRARY_PATH:大多数情况下不需要,但要知道
PostgreSQL 的动态库放在/usr/pgsql-15/lib。官方 RPM 在编译时已经写入了 RPATH(运行时库搜索路径),所以正常情况下,你直接运行/usr/pgsql-15/bin/psql不会出现找不到libpq.so.5的问题。
但有一种情况很典型:你把psql或者pg_dump复制到另外一台机器、换个目录执行,或者用了某些第三方编译版本,这时候可能会看到下面这种报错:
psql: error while loading shared libraries: libpq.so.5: cannot open shared object file: No such file or directory解决办法也很直接:
export LD_LIBRARY_PATH=/usr/pgsql-15/lib我个人不推荐默认给所有用户全局设置这个变量。原因很简单:它会影响系统里其他程序的动态库加载行为,容易引发一些莫名其妙的“库冲突”。只有当你确实遇到上述报错时,再考虑把它加进脚本或临时会话,用完后恢复。
2.4 MANPATH 和 PGHOST:属于锦上添花
MANPATH用来让man psql找到手册页,值一般是/usr/pgsql-15/share/man。这个变量配不配都不影响功能,但配上以后查文档确实方便。
PGHOST则是给 psql 提供默认连接地址的。如果不设置,psql 默认走本地 unix socket,连接的用户名默认取当前系统用户名。在默认的pg_hba.conf里,本地连接通常走peer认证。这些细节很多新手第一次接触时会困惑,但环境变量本身只是“给客户端一个默认值”,并不是安全配置。
2.5 为什么服务不用环境变量,我们却一定要配
这个问题值得想清楚。postgresql-15.service是 systemd 直接拉起的,systemd 启动进程时并不经过你的 bash,所以你的/etc/profile、~/.bashrc设置对它都没有意义。但人类和脚本不一样,我们打开终端,敲psql,都希望通过交互式 shell 直接进入数据库,所以环境变量需要配置在 shell 的启动文件里,让每次打开终端、切换用户时自动加载。这就是“服务靠 systemd,运维靠环境变量”的分工逻辑。
3. 实操配置:三套方案,按场景对号入座
下面给出三种实际的配置方式,覆盖最常见的服务器场景。你可以根据自己的角色选一套用。
3.1 全局方案:写 /etc/profile.d/pgsql15.sh
如果服务器上多个系统用户都可能用到 PostgreSQL 客户端,最好写到全局配置里。/etc/profile.d/下的.sh文件会在所有 bash 登录 shell 启动时被自动读取,这是 Red Hat 系列 Linux 的标准做法。
新建一个脚本:
cat > /etc/profile.d/pgsql15.sh << 'EOF' export PATH=/usr/pgsql-15/bin:$PATH export PGDATA=/var/lib/pgsql/15/data export MANPATH=/usr/pgsql-15/share/man:${MANPATH:-} EOF然后重新登录,或者手动加载一次:
source /etc/profile.d/pgsql15.sh验证:
which psql psql --version pg_config --bindir执行输出里应该能看到/usr/pgsql-15/bin/psql。
这里有一个经验:PATH 建议把/usr/pgsql-15/bin放到最前面。这样如果你机器上还装了旧版本 PostgreSQL 或者其他发行版自带的 psql,当前 shell 会优先找到新版 15 的命令。副作用是可能会“屏蔽”掉同名的旧命令,所以生产环境最好先which psql确认一下,别让新版本覆盖了预期行为。
3.2 单用户方案:只给 postgres 用户配置
很多维护操作是在postgres用户下进行的,比如备份、恢复、日常维护。给postgres用户单独配置环境变量,可以避免影响其他系统用户。
用 root 编辑家目录下的登录脚本:
cat >> /var/lib/pgsql/.bash_profile << 'EOF' # PostgreSQL 15 environment export PATH=/usr/pgsql-15/bin:$PATH export PGDATA=/var/lib/pgsql/15/data export MANPATH=/usr/pgsql-15/share/man:${MANPATH:-} EOF这里有个细节,postgres用户的家目录下同时会有.bash_profile和.bashrc。.bash_profile是登录 shell 才读取的,.bashrc是所有交互式子 shell 都会读取的。实际维护时,我更推荐把环境变量写在.bash_profile里,这样通过sudo -iu postgres或su - postgres进入一个“登录式”环境时才会加载,非登录式执行命令时不加载,逻辑更清晰。
进入验证:
sudo -iu postgres psql --version3.3 临时方案:不修改任何配置文件,直接执行
有时候你只是想跑一条 SQL,不想动全局配置,那就不需要配环境变量,直接写全路径就行。这种方案最稳妥,也是我最常用的临时排障手段:
sudo -u postgres /usr/pgsql-15/bin/psql -c "SELECT version();"如果你确实想用psql而不写全路径,可以用一次性的环境变量方式:
sudo -iu postgres sh -lc 'psql --version'注意,这里推荐的是-iu而不是-u,原因下一节详细说。
3.4 sudo -u 和 sudo -iu 的差别,新手经常踩坑
为什么强调-iu?因为sudo -u postgres psql这样的写法,在绝大多数发行版上仍然会报command not found。问题就出在 sudo 自己的secure_path机制上:即使你的 root 用户已经在当前 shell 里 export 了 PATH,sudo 也会用/etc/sudoers里定义的一套“安全 PATH”覆盖掉它,这套 PATH 里一般没有/usr/pgsql-15/bin。
换成sudo -iu postgres后,sudo 会模拟一次登录过程,读取postgres用户的.bash_profile,环境变量才会正确生效。所以:
# 可能报错 sudo -u postgres psql # 推荐 sudo -iu postgres psql # 或者完全不依赖环境变量 sudo -u postgres /usr/pgsql-15/bin/psql如果你需要执行一段带多个命令的维护脚本,我习惯这样写:
sudo -iu postgres bash -lc 'pg_ctl -D $PGDATA status'这里的bash -lc是让 bash 以登录 shell 方式运行,从而把.bash_profile里设置的变量都带进来。
4. 环境变量的进阶用法:多版本共存和自动化脚本
环境变量不只是“配一次就完事”,在真实服务器上,你还会遇到更多具体情况。
4.1 多版本共存:怎么在 PostgreSQL 14、15、16 之间切换
官方仓库支持在一台机器上同时安装多个大版本,目录分别是/usr/pgsql-14/bin、/usr/pgsql-15/bin、/usr/pgsql-16/bin。如果你经常需要切换版本,可以用一个小函数解决。把它放到/etc/profile.d/pgsql_multi.sh或者某个系统用户的.bashrc里:
switch_pg() { local ver="${1:?Usage: switch_pg <version>}" export PATH=$(printf '%s' "$PATH" | \ sed -E 's#(^|:/usr/pgsql-[0-9]+/bin)(:|$)#\2#g' | sed 's#^:##') export PATH="/usr/pgsql-${ver}/bin:$PATH" export PGDATA="/var/lib/pgsql/${ver}/data" export MANPATH="/usr/pgsql-${ver}/share/man:${MANPATH:-}" psql --version }用法:
switch_pg 15 which psql pg_config --version这个函数的思路是先从 PATH 里移除原本的/usr/pgsql-*路径,再插入要切换的新版本路径,避免 PATH 里堆积越来越多的旧路径。实际项目里如果只有一台开发机,直接写两个 alias 更省事,但放到自动化脚本里时,这招比较管用。
4.2 自动化脚本:别赌环境变量一定存在
写备份脚本或者定时任务时,最忌讳的一件事就是“假设用户已经配置好环境变量”。cron 执行脚本时的 PATH 非常精简,往往只有/usr/bin:/bin,你写在/etc/profile.d里的东西它未必读取。
所以我的经验是:脚本里要么写绝对路径,要么在脚本开头主动 source 你需要的环境。比如下面这种写法:
#!/bin/bash source /etc/profile.d/pgsql15.sh || true PGDATA=/var/lib/pgsql/15/data BINDIR=/usr/pgsql-15/bin "$BINDIR/pg_dump" -h 127.0.0.1 -U backup dbname | gzip > /backup/dbname.sql.gz越是关键的生产任务,越不要依赖“交互式用户登录后才有环境变量”这种脆弱前提。写死路径看起来很土,但排障时非常省心。
4.3 客户端工具和驱动:环境变量影响面比你想的大
Python、Java、PHP 这些程序连接 PostgreSQL 时,走的是各自的 libpq 客户端库,和 shell 环境变量并没有直接关系。但如果你在 shell 脚本里调用了psql、pg_dump,或者通过ssh远程执行命令,那环境变量又变得重要了。举个实际场景:
ssh dbserver "psql -c 'SELECT 1'"如果目标服务器上/usr/pgsql-15/bin不在 PATH 里,这条命令大概率失败。解决办法是写全路径,或者让目标 shell 加载 profile:
ssh dbserver "source /etc/profile.d/pgsql15.sh && psql -c 'SELECT 1'"理解了这点,你就明白环境变量不是“只在终端输入时管用”,它本质上影响的是所有非 systemd 发起的进程。
5. 避坑笔记:环境变量相关的典型报错与排查
环境变量本身不难,难的是遇到报错时快速定位方向。下面几条都是我在实际运维中见过的,挨个说清楚。
5.1 command not found:先分清是环境变量问题,还是安装问题
这个报错最常见,但原因不一定只有一个。按顺序排查:
# 1. 看安装包在不在 rpm -q postgresql15-server # 2. 看二进制目录在不在 ls /usr/pgsql-15/bin/psql # 3. 看 PATH 里有没有相关路径 echo "$PATH" | tr ':' '\n' | grep pgsql如果目录存在而 PATH 里没有,那就是环境变量没配好。如果目录都不存在,说明包没装成功,问题不在环境变量而在安装环节。
5.2 libpq.so.5 找不到:动态库路径问题
报错长这样:
psql: error while loading shared libraries: libpq.so.5: cannot open shared object file: No such file or directory常见原因是你把某个二进制从系统里拷出来,或者手动编译了一个程序但没有连接正确的 libpq。处理方式:
export LD_LIBRARY_PATH=/usr/pgsql-15/lib psql --version如果生效,就说明二进制本身能跑,只是“找不到库”。这时候再看你是不是需要全局配置。我见过有人在全局写死了LD_LIBRARY_PATH,结果其他服务加载了不兼容的动态库,反而更难排查。建议保持最小影响范围。
5.3 could not connect to server: No such file or directory
这个报错说明psql已经找到了,但它想连接的服务端 socket 文件并不存在。排障方向是:
systemctl status postgresql-15如果服务没有启动,先启动再看。如果服务已启动,检查 socket 目录。RPM 包默认的 unix socket 目录一般在/var/run/postgresql或数据目录内,具体看postgresql.conf里的unix_socket_directories:
sudo -u postgres /usr/pgsql-15/bin/psql -c "SHOW unix_socket_directories;"还有一种情况是你设置了PGHOST指向了一个错误路径,导致 psql 去别的地方找 socket。用unset PGHOST可以快速排除这个变量对排查的干扰。
5.4 FATAL: password authentication failed
这个其实和环境变量关系不大,但因为它紧跟在“终于能执行 psql”之后出现,所以我必须提一下。默认 RPM 安装完成后,pg_hba.conf中本地 unix socket 连接通常是peer认证,TCP 连接可能是scram-sha-256。所谓peer认证的含义是“操作系统用户名必须和数据库用户名一致,并且不需要密码”。
所以当你执行:
sudo -iu postgres psql不需要输入密码就能直接以postgres数据库用户身份进入。而如果用psql -h 127.0.0.1 -U postgres -W这种方式走 TCP,就需要设置数据库密码。这就是很多人“把环境变量配好了仍然连不上”的原因,并不是环境变量的问题,而是认证方式的问题。
如果只是为了日常运维,建议直接走本地 peer 认证,不要折腾密码。如果确实需要远程连接,那就单独处理认证和网络配置,别混在一起。
5.5 常见问题速查表
| 报错信息 | 可能原因 | 建议处理 |
|---|---|---|
psql: command not found | PATH 未包含/usr/pgsql-15/bin | 配置环境变量或使用全路径 |
libpq.so.5: cannot open shared object file | 动态库路径不对 | export LD_LIBRARY_PATH=/usr/pgsql-15/lib |
could not connect to server: No such file or directory | 服务未启动或 socket 路径不对 | 启动服务,检查unix_socket_directories |
FATAL: password authentication failed | 认证方式不匹配 | 按pg_hba.conf确认认证方式,设置对应密码 |
Permission denied访问数据目录 | 数据目录属主不是 postgres | 用chown -R postgres:postgres修复 |
5.6 一条命令确认环境变量是否生效
最后推荐一个组合验证:
which psql && psql --version && pg_config --bindirwhich psql解决“找没找到”的问题,psql --version确认版本,pg_config --bindir进一步确认当前环境用的是哪个安装目录。如果这三条输出都合理,环境变量这关基本就过了。
6. 我的实操体会:环境变量是给人和脚本用的,不是给服务用的
聊到这儿,再往回看“PostgreSQL 15 使用 yum 安装后环境变量信息”这个标题,核心其实就一句话:systemd 启动 PostgreSQL 不需要你配环境变量,但人要用 psql、脚本要调 pg_dump,就必须让 shell 知道命令在哪里。
我在真实服务器上攒下来的几条经验:
第一,别图省事把psql直接软链到/usr/local/bin。软链一次看起来很快,等你在同一台机器上装了 PostgreSQL 14 和 15,再一执行psql --version就分不清当前到底连的是哪个版本,生产环境出这种事非常吓人。保留/usr/pgsql-15/bin这样带版本号的路径,反而是一种安全标识。
第二,生产服务器上统一走/etc/profile.d配置,但不要把机器上所有环境变量都塞进同一个文件。我看到有人把 JDK、Python、PostgreSQL 的环境变量全写在一个env.sh里,出了问题谁都说不清是哪个变量把命令搞乱了。分文件写,命名清楚,出问题直接删掉对应文件重开终端,是最快的回滚方式。
第三,写自动化脚本时尽量用绝对路径。你可以不信任任何人的.bashrc,但不能不信任文件系统上确实存在的二进制。/usr/pgsql-15/bin/pg_dump虽然难看,但一到凌晨两点的 cron 任务出问题时,你会感谢这几个字节的确定性。
如果你正在一台刚用 yum 装完 PostgreSQL 15 的机器上,看到psql敲不出来,我建议你先运行一下rpm -qa | grep postgresql确认安装成功,再创建/etc/profile.d/pgsql15.sh写入 PATH 和 PGDATA,然后重新登录一次。整个过程不到三分钟,之后你就能正常用 psql、pg_dump 和 pg_ctl 了。环境变量这东西,明白了原理之后会觉得很直白:它不会让数据库跑得更快,但能让维护数据库的人少生很多气。