How to Install and Configure PostgreSQL on Fedora (Complete Guide)

Install PostgreSQL on Fedora using DNF, initialize the database, and start the service with these three commands.

You need a database that actually stays up

You just finished deploying a new web application and the database layer is missing. You run dnf install postgresql and expect a working database. Instead, the service fails to start, or the terminal drops you into a shell where you cannot create a role. The package is installed, but the database cluster does not exist yet. This is the exact moment most new Fedora users get stuck.

What PostgreSQL actually does on Fedora

PostgreSQL separates the server software from the data directory. The dnf transaction only drops binaries, libraries, and default configuration templates onto your disk. It does not create the actual database files. Think of it like buying a filing cabinet. The package manager delivers the cabinet and the instruction manual. You still have to assemble it, label the drawers, and set the combination lock before you can store documents. That assembly step is the database cluster initialization.

Fedora keeps this step explicit so you control where the data lives and how the authentication rules are set. The initialization process creates a data directory, generates system catalogs, sets up the default superuser, and writes the initial postgresql.conf and pg_hba.conf files. Until that directory exists, the postgresql.service unit has nothing to manage. The systemd service simply points to whatever data directory you specify during initialization.

Run postgresql-setup --initdb before you start the service. The daemon will refuse to launch without a valid cluster.

Install and initialize the cluster

Here is how to pull the packages, create the data directory, and register the service with systemd.

sudo dnf install -y postgresql postgresql-server
# Pulls the core server binaries and the setup utility
# The -y flag skips the interactive confirmation prompt
# Fedora's default repos contain the stable release matching your OS version

sudo postgresql-setup --initdb
# Creates /var/lib/pgsql/data with system catalogs and default configs
# Runs as root but drops privileges to the postgres user during setup
# Fails immediately if the data directory already exists or is non-empty

sudo systemctl enable --now postgresql
# Registers the unit in the default target for automatic boot start
# The --now flag starts the service immediately after enabling
# systemd reads the ExecStart path from /usr/lib/systemd/system/postgresql.service

The installation places runtime files in /var/lib/pgsql/data. Configuration overrides belong in /etc/postgresql/. Fedora follows the standard Linux convention where /usr/lib/ ships with the package and /etc/ holds user modifications. Never edit files directly in /usr/lib/. Your changes will vanish during a dnf upgrade --refresh. Always place custom settings in /etc/postgresql/ and let the package manager handle the base templates.

Here is how to check whether the service is actually running and listening on the expected port.

sudo systemctl status postgresql
# Shows active state, recent journal lines, and the main PID
# The output confirms whether systemd considers the unit healthy
# Use this before restarting to avoid masking real errors

ss -tlnp | grep 5432
# Lists TCP sockets in listening state with process names
# Confirms PostgreSQL bound to 0.0.0.0 or 127.0.0.1 on port 5432
# Returns nothing if the service failed to bind or is still starting

Check the socket output before you proceed. A missing listener means the service is not ready for connections.

Configure authentication and network access

PostgreSQL uses two primary files for access control. postgresql.conf controls network binding and performance tuning. pg_hba.conf controls client authentication rules. The default Fedora setup restricts connections to localhost using peer authentication. That means the OS username must match the PostgreSQL role name.

Here is how to adjust the network binding so remote applications can reach the database.

# /etc/postgresql/postgresql.conf
# Uncomment and modify the listen_addresses directive
listen_addresses = 'localhost, 192.168.1.50'
# Accepts connections on the loopback interface and your LAN IP
# Use '*' to bind to all interfaces, but restrict with firewall rules
# Changes require a service reload to take effect

Here is how to update the authentication rules to allow password-based access for a specific application user.

# /etc/postgresql/pg_hba.conf
# Append these lines at the bottom of the file
host    myapp_db    myapp_user    192.168.1.0/24    scram-sha-256
host    replication replicator    192.168.1.0/24    md5
# The first line allows the app user to connect from the local subnet
# scram-sha-256 is the modern default and provides strong password hashing
# The second line permits streaming replication from backup servers
# Always place specific rules before general catch-all rules

Reload the configuration without dropping active connections.

sudo systemctl reload postgresql
# Sends SIGHUP to the postmaster process
# PostgreSQL re-reads pg_hba.conf and postgresql.conf in memory
# Existing client sessions remain intact and unaffected

Run firewall-cmd --reload after every rule change. Otherwise the runtime config and the persistent config diverge, and your remote connections will time out.

Verify the installation

Here is how to drop into the default superuser shell and confirm the cluster is operational.

sudo -u postgres psql
# Switches to the postgres system user and launches the interactive CLI
# The peer authentication method matches the OS user to the DB role
# You should see the psql prompt without a password prompt

psql -c "SELECT version();"
# Runs a single query and exits the session
# Returns the compiled PostgreSQL version and build flags
# Confirms the server process is accepting queries correctly

Create a test database and a non-superuser role to validate authentication.

sudo -u postgres createuser --interactive testuser
# Prompts for role options and creates the new database user
# The --interactive flag prevents accidental superuser grants
# Always create application roles instead of connecting as postgres

sudo -u postgres createdb --owner testuser testdb
# Creates a new database and assigns ownership to the new role
# The owner can create tables and manage permissions inside testdb
# Verify access by connecting with the new credentials

Run journalctl -xeu postgresql if anything looks wrong. The x flag adds explanatory text and the e flag jumps to the end. Most sysadmins type this muscle-memory style when debugging service failures.

Common pitfalls and what the error looks like

The postgresql-setup --initdb command will refuse to proceed and print Error: Data directory is not empty. The cluster already exists. Remove the old directory or point the setup command to a fresh path. Do not force overwrite a running database.

If you see [FAILED] Failed to start postgresql.service during boot, your network configuration probably references a missing interface name or a conflicting port. Check journalctl -xeu postgresql for the exact binding failure. SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. Fedora enforces strict context labels on /var/lib/pgsql/data. Running initdb as root without the setup wrapper breaks the SELinux context and blocks the daemon from reading its own files.

The psql client will print FATAL: password authentication failed for user "appuser" when pg_hba.conf expects scram-sha-256 but the client sends md5. PostgreSQL matches the first rule that fits the connection parameters. A misplaced trust rule higher in the file will silently override your password settings. Always audit the top of pg_hba.conf before troubleshooting authentication.

A botched configuration reload can leave you unable to connect. Run systemctl status postgresql first. Read the actual error before guessing.

When to use PostgreSQL versus alternatives

Use PostgreSQL when you need strict ACID compliance, complex joins, and extensible data types like JSONB or geometric shapes. Use MariaDB when you are running legacy applications that depend on MySQL wire protocol compatibility and stored procedure syntax. Use Redis when you need sub-millisecond key-value lookups, pub/sub messaging, or in-memory session caching. Use SQLite when you are building embedded applications, local development tools, or lightweight desktop software that requires a single file database. Stay on the upstream PostgreSQL if you only deviate from the defaults occasionally.

Trust the package manager. Manual file edits drift, snapshots stay.

Where to go next