yum装完PostgreSQL 15后psql找不到?环境变量配置详解 刚在一台 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 找不到 psqlpsql: 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 了 PATHsudo 也会用/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 加载 profilessh 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_directoriessudo -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 foundPATH 未包含/usr/pgsql-15/bin配置环境变量或使用全路径libpq.so.5: cannot open shared object file动态库路径不对export LD_LIBRARY_PATH/usr/pgsql-15/libcould not connect to server: No such file or directory服务未启动或 socket 路径不对启动服务检查unix_socket_directoriesFATAL: 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 了。环境变量这东西明白了原理之后会觉得很直白它不会让数据库跑得更快但能让维护数据库的人少生很多气。