
Fedora 45 shipped in early November 2026, and the first thing many admins do on a fresh install is get a database running. PostgreSQL on Fedora looks easy. Run dnf install, start the service, done. Then the service refuses to start, or psql says the role doesn’t exist, or the app on another host gets “connection refused” while the firewall is wide open. Each of those failures has a simple cause. Fedora is not Ubuntu, and the differences matter.
Debian and Ubuntu create a working cluster the moment the package is installed. Fedora, like RHEL and AlmaLinux, installs the binaries and stops there. You initialize the cluster yourself, start the service yourself, and deal with SELinux, which is enforcing by default. Admins who move between distributions get caught by this all the time. The packages themselves are fine, and the habits are what trip people up.
This guide covers a complete PostgreSQL installation on Fedora 45. It starts with the packaged version from Fedora’s own repositories, then covers initializing the cluster, authentication, remote access, firewalld, SELinux, tuning, backups, upgrades and troubleshooting. Most commands carry over to AlmaLinux, Rocky Linux and RHEL with small changes, and the differences are marked where they matter. The goal is a database you would trust in front of real traffic, not one that merely starts.
Which PostgreSQL Version Ships With Fedora 45?
Fedora’s package tracker lists postgresql-server 18.3 for Fedora 45 [8]. The package source is postgresql18, which shows that Fedora now uses a versioned package layout for PostgreSQL. Fedora’s server documentation also notes that PostgreSQL server setup is part of the distribution’s release criteria [2], so the default package gets proper testing before release.
Check what your own system offers before installing:
dnf info postgresql-server
dnf list --available 'postgresql*-server'
Minor versions move fast. The 18.3 build listed today will be replaced by newer 18.x updates through the normal update channel, so your installed number may be higher. That is how it should work. Minor releases carry bug and security fixes only, and they never change the on-disk format.
Fedora Packages or the PGDG Repository?
There are two realistic sources.
- Fedora repositories: Zero extra setup, updates arrive with the rest of the system, and the packages are integrated with Fedora’s SELinux policy and systemd units. This is the right default for most servers and developer machines.
- PGDG (the official PostgreSQL project repository): Choose it when you must pin a specific major version, such as an older one your application vendor certifies, or when you need several majors side by side. Prisma’s guide points out that PGDG’s Fedora packages are only built for x86_64, so ARM machines should stay with Fedora’s packages [3].
A practical rule: use the Fedora package unless a written requirement says otherwise. Mixing both sources on one host is the quickest way to end up with two psql binaries and a confusing PATH.
Before You Start: Prerequisites
You need a Fedora 45 machine (Server, Workstation or a minimal cloud image), a user with sudo rights, and a working network connection. For production, plan the disk layout first. PostgreSQL data lives in /var/lib/pgsql by default, and moving it later is possible but annoying.
Bring the system fully up to date first:
sudo dnf upgrade --refresh -y
sudo reboot
The reboot is worth it if a new kernel arrived. Starting a database on a half-updated system makes later debugging harder, because you can’t tell whether a problem comes from the new install or from pending changes.
Also confirm SELinux and the firewall state, since both affect what comes next:
getenforce
sudo systemctl status firewalld --no-pager
Leave SELinux in Enforcing mode. Disabling it is the usual forum advice and almost always the wrong fix. Later sections show how to handle it properly.
Step 1: Install the PostgreSQL Server Packages
Install the server and the contrib modules:
sudo dnf install -y postgresql-server postgresql-contrib
Fedora’s own quick-start documentation uses exactly this pair of packages [11], and Fedora’s QA test case for server installation does the same [6]. The postgresql-contrib package adds extensions such as pg_stat_statements, pgcrypto, pg_trgm and hstore. You will want at least pg_stat_statements on any serious server, so install it now rather than hunting for it during an incident.
The dependencies come along automatically. In Fedora’s own example transaction, postgresql-server pulled in the postgresql client package and postgresql-private-libs [2].
Verify the install:
rpm -q postgresql-server
psql --version
Step 2: Initialize the Database Cluster
Here is where Fedora differs from Debian. Nothing exists yet. There is no data directory, no postgresql.conf and no pg_hba.conf. Fedora’s documentation states plainly that initialization is a prerequisite for everything else [2]. Run:
sudo postgresql-setup --initdb
The Fedora Quick Docs variant adds --unit postgresql, which is useful if you run several instances, though it isn’t required for a single default one [11]. This command creates the config files, including postgresql.conf and pg_hba.conf [11], inside /var/lib/pgsql/data.
Initializing With Better Options
The default initialization works, but production deserves a few deliberate choices. These can only be set at creation time (checksums can be changed offline later, but encoding and locale cannot), so decide now. The PGSETUP_INITDB_OPTIONS environment variable passes options through to initdb. Crunchy Data’s RPM guide demonstrates the pattern with data checksums, using sudo -E to preserve the variable [5].
sudo PGSETUP_INITDB_OPTIONS="--data-checksums --encoding=UTF8 --locale=C.UTF-8" postgresql-setup --initdb
Why these?
- Data checksums let PostgreSQL detect silent corruption in data pages. The CPU cost is small on modern hardware, and the first time a flaky SSD or bad RAID controller damages a page, you will be glad to get an error instead of quietly wrong data.
- UTF8 encoding is the sane default for anything touching international text. Indonesian, Japanese, emoji in user comments: all fine.
- C.UTF-8 locale gives fast, predictable sorting and avoids index breakage when glibc collation rules change between OS upgrades. That glibc issue has bitten real production systems after distribution upgrades, because indexes built under one collation order become subtly wrong under another.
If you already ran a plain --initdb and need to start over on an empty test box, stop the service and remove the data directory contents before re-running. Never do this on a system holding data.
Step 3: Enable and Start the Service
sudo systemctl enable --now postgresql
sudo systemctl status postgresql --no-pager
The --now flag enables the service at boot and starts it immediately, the same pattern shown in Prisma’s Fedora instructions [3]. Active (running) means success.
Check that the server accepts connections:
pg_isready
sudo -u postgres psql -c "SELECT version();"
The postgres operating system account owns the data directory and the server process. Becoming it with sudo -u postgres is the normal route into a fresh cluster, because the default pg_hba.conf uses peer authentication for local socket connections. More on that shortly.
Step 4: Create Roles and Databases
Resist the temptation to let applications connect as the postgres superuser. A leaked connection string then means a compromised server. Create a role and a database per application instead.
sudo -u postgres psql
CREATE ROLE appuser WITH LOGIN PASSWORD 'use-a-long-random-secret';
CREATE DATABASE appdb OWNER appuser ENCODING 'UTF8' TEMPLATE template0;
REVOKE ALL ON DATABASE appdb FROM PUBLIC;
GRANT CONNECT ON DATABASE appdb TO appuser;
\q
The REVOKE ... FROM PUBLIC line removes the default permission that lets any role connect to any database. It is a small habit that closes a real gap on multi-tenant servers.
Generate a strong password rather than inventing one:
openssl rand -base64 24
Test the new role over TCP:
psql -h 127.0.0.1 -U appuser -d appdb
If that fails with an authentication error, do not panic. It usually points at pg_hba.conf, which is the next topic.
Understanding pg_hba.conf and Authentication
PostgreSQL decides who may connect through /var/lib/pgsql/data/pg_hba.conf. Rules are read top to bottom and the first match wins. Open it:
sudo less /var/lib/pgsql/data/pg_hba.conf
On a new Fedora cluster, local connections use peer (operating system user must match database role), and TCP connections from localhost use scram-sha-256 in current releases. If you see md5 or ident in an older file, switch to SCRAM. It is the modern password mechanism and resists the weaknesses of MD5 hashing.
A typical production-minded setup for an app server on a private network looks like this:
# TYPE DATABASE USER ADDRESS METHOD
local all postgres peer
local all all peer
host appdb appuser 127.0.0.1/32 scram-sha-256
host appdb appuser 10.20.30.0/24 scram-sha-256
Note the narrow CIDR range. Writing 0.0.0.0/0 here is how databases end up on exposed-database scanning lists. Reload without dropping connections:
sudo systemctl reload postgresql
Make sure password encryption is set to SCRAM in postgresql.conf before creating roles:
password_encryption = scram-sha-256
Passwords created under a different setting remain stored in the old format until reset, so check this early.
Enabling Remote Connections Safely
By default PostgreSQL listens only on localhost. That is a good default, and plenty of setups should leave it alone. When the application runs on another machine, change two things.
Edit postgresql.conf:
sudo nano /var/lib/pgsql/data/postgresql.conf
listen_addresses = 'localhost,10.20.30.5'
port = 5432
Use the server’s private interface address, not '*', unless a firewall guarantees nothing public can reach the port. Listening addresses require a full restart:
sudo systemctl restart postgresql
ss -tlnp | grep 5432
The ss output should show the addresses you configured.
Opening the Firewall With firewalld
Fedora Server ships with firewalld active. Fedora’s own QA test case uses the built-in service definition [6]:
sudo firewall-cmd --permanent --add-service=postgresql
sudo firewall-cmd --reload
That opens 5432 to everyone who can reach the zone. A tighter option is a rich rule limiting the source network:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.20.30.0/24" service name="postgresql" accept'
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
If you use the rich rule, do not also add the open service, or the broad rule wins. Defense in depth means the firewall, listen_addresses and pg_hba.conf each restrict access independently. If one is misconfigured, the others still hold.
SELinux and PostgreSQL
SELinux is the part that makes admins reach for setenforce 0. Don’t. The default policy already knows PostgreSQL, so the standard install works with no changes. Trouble starts when you deviate: a custom data directory, a non-standard port, or an application connecting from a web server process.
Moving the Data Directory
Say a dedicated NVMe volume is mounted at /data/pgsql. Stop the service, copy the data with attributes, and label the new path:
sudo systemctl stop postgresql
sudo mkdir -p /data/pgsql
sudo rsync -aHAX /var/lib/pgsql/data/ /data/pgsql/data/
sudo semanage fcontext -a -t postgresql_db_t "/data/pgsql(/.*)?"
sudo restorecon -Rv /data/pgsql
If semanage is missing, install it with sudo dnf install -y policycoreutils-python-utils. That package appears in other Fedora guides as a standard dependency [12]. Then point systemd at the new location with a drop-in:
sudo systemctl edit postgresql
[Service]
Environment=PGDATA=/data/pgsql/data
Reload and start:
sudo systemctl daemon-reload
sudo systemctl start postgresql
Web Apps Connecting to the Database
If PHP-FPM or Nginx on the same host cannot reach PostgreSQL, SELinux may be blocking the network connection from the web context. Check before changing anything:
sudo ausearch -m avc -ts recent
sudo getsebool httpd_can_network_connect_db
sudo setsebool -P httpd_can_network_connect_db on
The -P flag makes the change persistent across reboots. This is a targeted switch, far safer than turning SELinux off.
Troubleshooting Common Errors
“Job for postgresql.service failed” or an empty data directory
Almost always the cluster was never initialized. Check:
sudo journalctl -xeu postgresql --no-pager | tail -30
ls /var/lib/pgsql/data
If the directory is empty, run sudo postgresql-setup --initdb, then start the service again. This is the single most common first-time Fedora mistake, and it ties directly to the setup flow documented by Fedora [2].
“psql: error: connection to server on socket failed: No such file or directory”
The server isn’t running or is using a different socket path. Run systemctl status postgresql, then pg_isready. If it’s stopped, read the journal for the real reason.
“FATAL: Peer authentication failed for user”
You connected through the local socket as a Linux user whose name doesn’t match the database role. Either use TCP (-h 127.0.0.1) with a password, or switch to the matching OS user. Avoid changing peer to trust just to make the error disappear.
“FATAL: password authentication failed”
Check that the role really has a password, and that the password was set under scram-sha-256. Reset it:
ALTER ROLE appuser WITH PASSWORD 'new-secret';
Also confirm that the right pg_hba.conf line matches your source address, since the first matching line decides.
“Connection refused” from another host
Work outward in layers. First ss -tlnp | grep 5432 to see if it listens on the right address. Then sudo firewall-cmd --list-all for the port. Then test from the client with nc -zv 10.20.30.5 5432. If the port is open but authentication fails, the issue sits in pg_hba.conf.
Permission denied on the data directory
sudo chown -R postgres:postgres /var/lib/pgsql/data
sudo chmod 700 /var/lib/pgsql/data
sudo restorecon -Rv /var/lib/pgsql
Wrong ownership or a wrong SELinux label after a manual copy causes this. Check ausearch -m avc -ts recent to confirm SELinux involvement.
“could not bind IPv4 address” or port already in use
Another process, perhaps a second PostgreSQL instance, holds 5432. Find it with sudo ss -tlnp | grep 5432, then stop it or change port in the config.
Disk full and a database that won’t start
A runaway WAL directory, usually because a replica or archiving process stopped consuming it, can fill the volume. Free space elsewhere first. Never delete files from pg_wal by hand; you can destroy the cluster. Fix the cause (archive command, stuck replication slot) and let PostgreSQL clean up itself.