PostgreSQL 15 is a solid choice for production servers that need a stable, well-supported database without chasing the latest major release. It ships with improved sorting performance, enhanced logical replication, and the MERGE command for upsert operations. The PGDG (PostgreSQL Global Development Group) maintains packages for RHEL-family distributions, so you get timely security patches without upgrading to a newer major version.
This guide installs PostgreSQL 15 from the official PGDG repository on Rocky Linux 9 and AlmaLinux 9. We cover installation, initialization, authentication setup, creating databases and users, configuring remote access, firewall rules, and SELinux. Every command was tested on a live Rocky Linux 9.5 server. If you need the latest major version instead, see the PostgreSQL 17 on Rocky Linux 10 guide.
Tested April 2026 on Rocky Linux 9.5 with PostgreSQL 15.17 from the PGDG repository, SELinux enforcing
Prerequisites
- Rocky Linux 9 or AlmaLinux 9 (tested with 9.5)
- Root or sudo access
- Firewall access to port 5432 if remote connections are needed
Install the PGDG Repository
Rocky Linux 9 ships PostgreSQL from its AppStream repository, but the version there may not be 15. The PGDG repository provides the exact version you want with consistent packaging.
Install the repository RPM:
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
Disable the built-in PostgreSQL module so it does not conflict with the PGDG packages:
sudo dnf -qy module disable postgresql
Install PostgreSQL 15
Install the server package, which pulls in the client and shared libraries automatically:
sudo dnf install -y postgresql15-server
Three packages are installed:
Installed:
postgresql15-15.17-1PGDG.rhel9.7.x86_64
postgresql15-libs-15.17-1PGDG.rhel9.7.x86_64
postgresql15-server-15.17-1PGDG.rhel9.7.x86_64
Verify the installed version:
/usr/pgsql-15/bin/psql --version
Confirms PostgreSQL 15.17:
psql (PostgreSQL) 15.17
Initialize and Start the Database
On RHEL-family distributions, PostgreSQL does not initialize the database cluster or start automatically after installation. You need to run the init script first.
Initialize the database cluster:
sudo /usr/pgsql-15/bin/postgresql-15-setup initdb
This creates the data directory at /var/lib/pgsql/15/data/ with the default configuration files:
Initializing database ... OK
Enable PostgreSQL to start at boot and start it now:
sudo systemctl enable --now postgresql-15
Check the service status:
systemctl status postgresql-15
The service should be active and running:
● postgresql-15.service - PostgreSQL 15 database server
Loaded: loaded (/usr/lib/systemd/system/postgresql-15.service; enabled; preset: disabled)
Active: active (running) since Fri 2026-04-03 14:55:45 EAT; 8ms ago
Docs: https://www.postgresql.org/docs/15/static/
Main PID: 469344 (postmaster)
Tasks: 7 (limit: 203278)
Memory: 18.3M
CGroup: /system.slice/postgresql-15.service
├─469344 /usr/pgsql-15/bin/postmaster -D /var/lib/pgsql/15/data/
├─469345 "postgres: logger "
├─469346 "postgres: checkpointer "
├─469347 "postgres: background writer "
├─469349 "postgres: walwriter "
Set the postgres User Password
PostgreSQL creates a system user called postgres with no password. By default, local connections use peer authentication, which means only the postgres OS user can connect to the database without a password. For password-based authentication (needed for applications and remote access), set a database password.
Connect to the PostgreSQL prompt:
sudo -u postgres psql
Set the password for the postgres database superuser:
ALTER USER postgres WITH PASSWORD 'YourStrongPassword';
\q
Replace YourStrongPassword with a strong, unique password. The \q command exits the psql prompt.
Create a Database and Application User
Production applications should never connect as the postgres superuser. Create a dedicated user and database for each application.
sudo -u postgres psql -c "CREATE USER appuser WITH PASSWORD 'SecureAppPass2026';"
sudo -u postgres psql -c "CREATE DATABASE appdb OWNER appuser;"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE appdb TO appuser;"
Verify the database was created:
sudo -u postgres psql -c "\l"
The appdb database appears with appuser as the owner:
List of databases
Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider
-----------+----------+----------+-------------+-------------+------------+-----------------
appdb | appuser | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc
(4 rows)
Test the connection as the new user:
psql -U appuser -d appdb -h 127.0.0.1 -c "SELECT version();"
You will be prompted for the password. The output confirms a successful connection:
version
------------------------------------------------------------------------------------------------------------
PostgreSQL 15.17 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 11.5.0 20240719 (Red Hat 11.5.0-11), 64-bit
(1 row)
Configure Authentication (pg_hba.conf)
The pg_hba.conf file controls who can connect, from where, and how they authenticate. The default configuration on PGDG installs looks like this:
local all all peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
This means local socket connections use peer (OS user must match database user), and TCP connections from localhost use scram-sha-256 (password required). For most setups, this is secure and sufficient.
If you want local socket connections to also require a password (recommended when multiple OS users share the server), change peer to scram-sha-256:
sudo vi /var/lib/pgsql/15/data/pg_hba.conf
Change the local connection line:
local all all scram-sha-256
Restart PostgreSQL to apply:
sudo systemctl restart postgresql-15
Enable Remote Connections
By default, PostgreSQL only listens on localhost. To allow connections from other servers or applications on the network, two changes are needed: the listen address and a pg_hba.conf rule.
Open the main configuration file:
sudo vi /var/lib/pgsql/15/data/postgresql.conf
Find the listen_addresses line and change it to listen on all interfaces, or a specific IP:
listen_addresses = '*'
Then add a rule to pg_hba.conf that allows connections from your network. Open the file:
sudo vi /var/lib/pgsql/15/data/pg_hba.conf
Add a line at the end for your subnet (adjust the CIDR to match your network):
# Allow connections from the 10.0.1.0/24 network
host all all 10.0.1.0/24 scram-sha-256
Restart PostgreSQL to apply both changes:
sudo systemctl restart postgresql-15
Verify PostgreSQL is now listening on all interfaces:
ss -tlnp | grep 5432
You should see 0.0.0.0:5432 instead of 127.0.0.1:5432.
Configure the Firewall
Rocky Linux 9 uses firewalld by default. Open port 5432 for PostgreSQL:
sudo firewall-cmd --permanent --add-service=postgresql
sudo firewall-cmd --reload
Verify the rule is active:
sudo firewall-cmd --list-services
You should see postgresql in the output alongside other allowed services like ssh.
SELinux Configuration
On Rocky Linux 9 with SELinux enforcing, PostgreSQL works on the default port (5432) without any changes. The postgresql_port_t SELinux type already allows TCP 5432 and 9898.
If you change PostgreSQL to a non-standard port, add the port to SELinux:
sudo semanage port -a -t postgresql_port_t -p tcp 5433
If PostgreSQL needs to write to a non-default directory (custom data directory or tablespace), set the correct SELinux context:
sudo semanage fcontext -a -t postgresql_db_t "/custom/pgdata(/.*)?"
sudo restorecon -Rv /custom/pgdata
Check for SELinux denials after any configuration change:
sudo ausearch -m avc -ts recent
Basic Performance Tuning
The default PostgreSQL configuration is conservative, designed for a server with 128 MB of RAM. Adjust these settings in /var/lib/pgsql/15/data/postgresql.conf based on your available memory:
sudo vi /var/lib/pgsql/15/data/postgresql.conf
Key settings to tune (example values for a server with 4 GB RAM):
# Memory
shared_buffers = 1GB # 25% of total RAM
effective_cache_size = 3GB # 75% of total RAM
work_mem = 16MB # Per-operation sort memory
maintenance_work_mem = 256MB # For VACUUM, CREATE INDEX
# WAL
wal_buffers = 16MB
max_wal_size = 2GB
# Connections
max_connections = 200
Restart after changing these settings:
sudo systemctl restart postgresql-15
For production databases, use PGTune to generate recommended values based on your server’s hardware and workload type. Once the database holds real data, protect it with a backup and point-in-time recovery strategy. For monitoring, see the PostgreSQL monitoring with Prometheus and Grafana guide.
Useful PostgreSQL Commands
| Task | Command |
|---|---|
| Connect as postgres | sudo -u postgres psql |
| Connect to specific database | psql -U user -d dbname -h host |
| List databases | \l |
| List tables | \dt |
| Create database | CREATE DATABASE name; |
| Create user | CREATE USER name WITH PASSWORD 'pass'; |
| Grant privileges | GRANT ALL ON DATABASE db TO user; |
| Show current user | SELECT current_user; |
| Show server version | SELECT version(); |
| Exit psql | \q |
| Reload config (no restart) | sudo -u postgres psql -c "SELECT pg_reload_conf();" |
| Check active connections | SELECT * FROM pg_stat_activity; |
File Paths Reference
| Item | Path |
|---|---|
| Data directory | /var/lib/pgsql/15/data/ |
| Main config | /var/lib/pgsql/15/data/postgresql.conf |
| Authentication config | /var/lib/pgsql/15/data/pg_hba.conf |
| Log files | /var/lib/pgsql/15/data/log/ |
| Binary directory | /usr/pgsql-15/bin/ |
| Systemd service | postgresql-15.service |
For the full command and shortcut reference, see the best PostgreSQL books for deeper learning. If you need vector search capabilities for AI workloads, the pgvector installation guide covers adding vector similarity search to this PostgreSQL instance.