pgAdmin’s own Fedora repository has no Fedora 45 tree yet. Its fedora-45-x86_64 directory returns 404 while the 43 and 44 trees are still there, so the install steps most guides copy from pgadmin.org stop at dnf install. To install pgAdmin 4 on Fedora 45 you use the pgadmin4 package from Fedora’s own repository and serve it in web mode through Apache. On Fedora 44 the upstream repository still works and ships a slightly newer build.
This guide covers both routes, the PostgreSQL side, the SELinux boolean and the pg_hba.conf change that pgAdmin needs before it can connect, plus the three errors the upstream repository throws on Fedora 45. Every command below was run on Fedora 45 and Fedora 44 lab VMs in November 2026 with SELinux enforcing, using pgAdmin 4 9.18 from Fedora and 9.19 from the pgAdmin repository.
Prerequisites
You need a Fedora machine you can reach over the network from the browser you’ll use, and an account with sudo. Web mode runs inside Apache, so it fits a server or a headless VM just as well as a workstation.
- Fedora 45 or Fedora 44, x86_64
- 2 GB RAM or more (the lab VMs had 4 GB)
- About 550 MB free disk for pgAdmin, Apache and their Python dependencies
- A PostgreSQL server to manage, local or remote
- TCP port 80 open from your desk to the Fedora host
If you just upgraded, check that the release really says 45 before picking a route, because the repository layout decides everything that follows. Our Fedora 44 to 45 upgrade guide covers the jump itself.
Pick the pgAdmin 4 install route
Your Fedora release decides the route, not taste. We tried both repositories on both releases, and the table records what each one did in the lab:
| Release | pgAdmin repository | Fedora repository | Use |
|---|---|---|---|
| Fedora 45 | No fedora-45 tree (404). Pinning the 44 tree installs 9.19 but web mode returns HTTP 500 | pgadmin4 9.18-1.fc45 plus pgadmin4-httpd, works in web mode | Fedora repository |
| Fedora 44 | fedora-44 tree with 9.19-1.fc44, setup-web.sh works | pgadmin4 9.18-1.fc44 is also available | pgAdmin repository |
The two packages are not interchangeable. Fedora’s build installs under /usr/lib/pgadmin4, runs on the system Python and serves at /pgadmin, while the upstream build ships its own Python virtual environment in /usr/pgadmin4 and serves at /pgadmin4. Pick one per machine and stick to it. Fedora also packages an unofficial desktop wrapper, pgadmin4-qt, which we did not test; everything here is web mode.
Install PostgreSQL on Fedora
pgAdmin is only a client, so it needs a database to talk to. If you already run PostgreSQL elsewhere, skip to the next section. For a local server, Fedora’s own postgresql-server package is enough; our PostgreSQL on Fedora guide covers tuning and the PGDG builds in more depth.
sudo dnf install postgresql-server
sudo postgresql-setup --initdb
sudo systemctl enable --now postgresql
Running initdb creates the cluster under /var/lib/pgsql/data, and the service will not start without it because the data directory is empty after the package install. Fedora ships the server bound to localhost only, so nothing on the network can reach port 5432 yet. That suits a pgAdmin box that manages its own database. The output looks like this.
* Initializing database in '/var/lib/pgsql/data'
* Initialized, logs are in /var/lib/pgsql/initdb_postgresql.log
Created symlink '/etc/systemd/system/multi-user.target.wants/postgresql.service' → '/usr/lib/systemd/system/postgresql.service'.
The postgres role has no password after initdb, and pgAdmin logs in over TCP with a password, so set one now. Pick your own value, since the one below is the throwaway the lab used. In production you would create a separate login role for pgAdmin rather than handing it the superuser, but the superuser keeps this walkthrough short.
sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD 'Db-Pass-2345';"
psql answers with ALTER ROLE. Fedora’s default pg_hba.conf still rejects that password over TCP, but leave it alone for now: the fix is shown later, next to the error it causes, so you can recognise it when it shows up on another box.
Install pgAdmin 4 on Fedora 45 from the Fedora repo
On Fedora 44 with the vendor packages, jump to the Fedora 44 section further down and come back for the login steps. On Fedora 45 the working package lives in the stock fedora repository. You need three packages: pgadmin4 for the application, pgadmin4-httpd for the Apache config, and httpd for the service unit.
sudo dnf install pgadmin4 pgadmin4-httpd httpd
Do not drop httpd from that line. On Fedora 45, pgadmin4-httpd pulls in httpd-core only, which carries the binary but no systemd unit. We installed the first two packages on their own and the service didn’t exist:
Failed to enable unit: Unit httpd.service does not exist
The full transaction is large because Fedora’s build uses system Python packages instead of a bundled virtual environment. On our minimal cloud image pgadmin4 and pgadmin4-httpd alone came to 142 packages and about 521 MB, with python3-botocore (119 MiB), python3-azure-mgmt-resource (53 MiB) and python3-babel (30 MiB) as the biggest pieces, pulled in for pgAdmin’s cloud deployment wizards and translations, and httpd added 5 more. A Workstation install already carries some of them, so expect a smaller transaction there. Confirm what landed.
rpm -q pgadmin4 pgadmin4-httpd httpd python3-mod_wsgi
All four packages should carry the fc45 tag, which means they came from Fedora and not from a pinned foreign tree:
pgadmin4-9.18-1.fc45.x86_64
pgadmin4-httpd-9.18-1.fc45.x86_64
httpd-2.4.69-1.fc45.x86_64
python3-mod_wsgi-5.0.2-10.fc45.x86_64
That python3-mod_wsgi line matters more than it looks. It is built against the system Python, and Fedora’s pgAdmin runs on the same interpreter, so the two always match after a dnf upgrade. That pairing is exactly what breaks on the vendor route on Fedora 45, as the last section shows, so a mismatched interpreter is the first thing to check if pgAdmin ever returns HTTP 500 after an upgrade.
Create the pgAdmin admin account
Fedora’s package has no setup-web.sh. The package creates /var/lib/pgadmin and /var/log/pgadmin owned by apache, and you build the configuration database with pgAdmin’s own setup.py. Run it as apache, because a database created as root ends up unreadable to the web server:
sudo -u apache [email protected] PGADMIN_SETUP_PASSWORD='Lab-Pass-2345' python3 /usr/lib/pgadmin4/setup.py setup-db
The email and password become the first pgAdmin login, so use your own. pgAdmin checks that the address looks like an email, but it never sends mail to it unless you configure SMTP, so [email protected] is fine on a lab box. The script prints a short banner and exits 0.
NOTE: Configuring authentication for SERVER mode.
pgAdmin 4 - Application Initialisation
======================================
Ownership is the part that goes wrong silently, because pgAdmin only reads the database when the first browser request arrives. Check that the files belong to apache now, so a permissions problem doesn’t show up later as a vague login error.
sudo ls -l /var/lib/pgadmin
You should see pgadmin4.db plus the session and storage directories, every one owned by apache:
total 196
drwx------. 1 apache apache 0 Nov 3 13:16 azurecredentialcache
-rw-------. 1 apache apache 200704 Nov 3 13:16 pgadmin4.db
drwx------. 1 apache apache 0 Nov 3 13:16 sessions
drwx------. 1 apache apache 0 Nov 3 13:16 storage
If you ever see root in that listing, you ran the command without -u apache. Fix it with sudo chown -R apache:apache /var/lib/pgadmin before starting Apache.
Start Apache and open pgAdmin to your LAN
pgAdmin has no service of its own in web mode. It lives inside Apache as a WSGI daemon process, so enabling Apache is what brings pgAdmin back after a reboot, and restarting Apache is how you restart pgAdmin.
sudo systemctl enable --now httpd
At this point a curl on the box itself gets a 200 from http://127.0.0.1/pgadmin/login, but a browser on another machine gets 403 Forbidden. Fedora’s config ships with Require local, and the Apache error log says so plainly: AH01630: client denied by server configuration: /usr/lib/pgadmin4/pgAdmin4.wsgi. That default is sensible, so widen it to your own subnet only. Open the file:
sudo vim /etc/httpd/conf.d/pgadmin4.conf
Add a Require ip line under Require local, using your LAN range instead of ours:
<IfModule wsgi_module>
WSGIDaemonProcess pgadmin processes=1 threads=8 python-home=/usr
WSGIScriptAlias /pgadmin /usr/lib/pgadmin4/pgAdmin4.wsgi
<Directory /usr/lib/pgadmin4>
WSGIProcessGroup pgadmin
WSGIApplicationGroup %{GLOBAL}
Require local
Require ip 192.168.1.0/24
</Directory>
</IfModule>
Test the syntax before reloading, since a typo here takes down every site on the Apache instance.
sudo apachectl configtest
sudo systemctl reload httpd
Syntax OK is what you want. The AH00558 warning about the server’s fully qualified domain name above it is harmless on a lab box; set ServerName in httpd.conf to silence it. After the reload, the same login URL that returned 403 from our desk returned 200.
Fedora Server and Workstation run firewalld, which blocks port 80 until you allow it. The cloud image we tested had no firewalld at all, so we installed it to run the same commands you will. You can skip this step only when sudo firewall-cmd --state answers with command not found.
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
sudo firewall-cmd --list-services
Both changes print success, and http now shows in the service list.
dhcpv6-client http mdns ssh
If you’d rather scope the rule to one source network in firewalld too, our firewalld guide for Fedora shows rich rules and zones. Plain HTTP is fine on a trusted LAN; anywhere else, put pgAdmin behind TLS before you type a database password into it.
Turn off the pgAdmin upgrade check
On the first login, Fedora 45 pops up a red <urlopen error [Errno 13] Permission denied> toast. That is pgAdmin calling pgadmin.org to check for a new version, and SELinux refusing outbound connections from httpd_t. The log in /var/log/pgadmin/pgadmin4.log names the caller:
File "/usr/lib/pgadmin4/pgadmin/misc/__init__.py", line 393, in upgrade_check
urllib.error.URLError: <urlopen error [Errno 13] Permission denied>
Do not open httpd_can_network_connect just for this. Updates come through dnf anyway, so the check adds nothing. Turn it off in /etc/pgadmin/config_system.py, which pgAdmin reads last and which no package owns. We first put the setting in /usr/lib/pgadmin4/config_local.py, then found that file is not marked as a config file in the RPM (rpm -qc pgadmin4 pgadmin4-httpd lists only /etc/httpd/conf.d/pgadmin4.conf), so the next pgAdmin update would overwrite it.
sudo mkdir -p /etc/pgadmin
echo "UPGRADE_CHECK_ENABLED = False" | sudo tee /etc/pgadmin/config_system.py
sudo systemctl restart httpd
On the next login the toast is gone. Confirm the setting took effect by asking pgAdmin’s own config loader, run as apache so it reads the files the way the web process does:
sudo -u apache python3 -c "import sys; sys.path.insert(0,'/usr/lib/pgadmin4'); import config; print('UPGRADE_CHECK_ENABLED =', config.UPGRADE_CHECK_ENABLED)"
It should print UPGRADE_CHECK_ENABLED = False. If it prints True, check the path and the spelling of the setting, because pgAdmin quietly ignores a variable name it doesn’t know. A Python syntax error in the file is louder: the check prints a traceback and the web app returns HTTP 500 until you fix it.
Install pgAdmin 4 on Fedora 44 from the pgAdmin repo
Fedora 44 readers can use the vendor packages, which run a release ahead of Fedora’s and come with setup-web.sh. Skip this section on Fedora 45. Install the repository package first:
sudo rpm -i https://ftp.postgresql.org/pub/pgadmin/pgadmin4/yum/pgadmin4-fedora-repo-2-1.noarch.rpm
RPM on Fedora 44 prints Header OpenPGP V4 RSA/SHA256 signature, key ID 8881b2a8210976f2: NOKEY as a warning and still installs the package. Then install the web package, which pulls pgadmin4-server and the matching python3-mod_wsgi:
sudo dnf install pgadmin4-web
dnf asks once to import key 0x210976F2 from /etc/pki/rpm-gpg/PGADMIN_PKG_KEY. Here is an excerpt of the 18-package transaction on our Fedora 44 VM, with Apache and its libraries left out:
Installing:
pgadmin4-web noarch 0:9.19-1.fc44 pgAdmin4 6.0 KiB
Installing dependencies:
pgadmin4-server x86_64 0:9.19-1.fc44 pgAdmin4 256.2 MiB
python3-mod_wsgi x86_64 0:5.0.2-7.fc44 fedora 5.6 MiB
Now run the vendor’s web setup. It creates the admin account, writes /etc/httpd/conf.d/pgadmin4.conf, sets the SELinux booleans and starts Apache. Without the environment variables it prompts for the email and password instead:
sudo [email protected] PGADMIN_SETUP_PASSWORD='Lab-Pass-2345' /usr/pgadmin4/bin/setup-web.sh --yes
Watch the last lines of the run, which tell you where to point the browser. Note the path is /pgadmin4 here, not Fedora’s /pgadmin:
Creating storage and log directories...
Configuring SELinux...
Created symlink '/etc/systemd/system/multi-user.target.wants/httpd.service' → '/usr/lib/systemd/system/httpd.service'.
Apache successfully enabled.
Apache successfully started.
You can now start using pgAdmin 4 in web mode at http://127.0.0.1/pgadmin4
The Apache error log on that box shows why it works on 44: mod_wsgi/5.0.2 Python/3.14, the same interpreter the vendor’s virtual environment was built for. Two things differ from Fedora’s package, and both matter for security. The vendor’s /etc/httpd/conf.d/pgadmin4.conf uses Require all granted, so the login page answers anyone who can reach your port 80. And setup-web.sh turns on the broad httpd_can_network_connect and httpd_tmp_exec SELinux booleans as well as httpd_can_network_connect_db, which is why Fedora 44 readers on this route never see the SELinux errors described below.
Restrict the vendor config to your network the same way. Open the file:
sudo vim /etc/httpd/conf.d/pgadmin4.conf
Replace Require all granted in the Apache 2.4 block so the Directory section reads:
<Directory /usr/pgadmin4/web/>
WSGIProcessGroup pgadmin
WSGIApplicationGroup %{GLOBAL}
<IfModule mod_authz_core.c>
# Apache 2.4
Require local
Require ip 192.168.1.0/24
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
Order Deny,Allow
Deny from All
Allow from 127.0.0.1
Allow from ::1
</IfModule>
</Directory>
Run sudo apachectl configtest and sudo systemctl reload httpd as on Fedora 45; our desk on the allowed subnet still got a 200 from /pgadmin4/login afterwards. The firewalld commands from the Fedora 45 section apply here unchanged, and so does the pg_hba.conf fix below if your PostgreSQL also comes from Fedora’s repository.
Log in to pgAdmin and register the server
Browse to http://10.0.1.50/pgadmin on Fedora 45, or http://10.0.1.50/pgadmin4 on Fedora 44 with the vendor build, replacing the address with your host’s. The web mode login page asks for the email and password from the setup step:

Expect the first load after login to take 10 to 30 seconds while the browser pulls the JavaScript bundle; later loads come from cache, so a long spinner on that first visit is not a fault. The dashboard opens with an empty Servers tree. Click Add New Server under Quick Links:

The Register Server dialog opens on the General tab. Type a Name for the entry (it only labels the tree node, so f45-local is fine), then switch to the Connection tab:

- 1Name
- 2Connection tab
Fill in the connection details for the PostgreSQL server you set up earlier. Use 127.0.0.1 rather than localhost for a local server, because the address decides which pg_hba.conf line PostgreSQL matches, and you will edit that line shortly.
- Host name/address: 127.0.0.1 for a server on the same box
- Username: postgres
- Password: the one set with ALTER USER
- Save

- 1Host name/address
- 2Username
- 3Password
- 4Save
Leave Port at 5432 and Maintenance database at postgres. Turn on Save password? if you don’t want to type it on every connect; pgAdmin stores it encrypted in its own database. On a fresh Fedora 45 install with Fedora’s PostgreSQL, Save fails twice before it works, and the next two sections deal with each failure. Fedora 44 readers on the vendor route skip the SELinux one but hit the ident error just the same.
Fix “Permission denied” on port 5432
The first Save comes back with connection is bad: connection to server at "127.0.0.1", port 5432 failed: Permission denied, followed by the familiar question about TCP/IP connections:

PostgreSQL is running and listening; the hint is misleading. The connection is made by the WSGI process inside Apache, which runs as httpd_t, and SELinux blocks httpd_t from database ports unless the httpd_can_network_connect_db boolean is on. Fedora’s package leaves it off. The vendor’s setup-web.sh turns it on for you, which is why Fedora 44 readers on that route never see this error.
sudo setsebool -P httpd_can_network_connect_db on
getsebool httpd_can_network_connect_db
getsebool now reports the boolean as on, and -P keeps it that way across reboots:
httpd_can_network_connect_db --> on
Keep SELinux enforcing. This boolean covers PostgreSQL’s port and other database ports, which is far narrower than httpd_can_network_connect, and setting enforcing to permissive would hide the next real problem. Our SELinux survival guide for Fedora explains how to find the boolean behind any denial.
Fix “Ident authentication failed for user postgres”
With SELinux out of the way, the second Save reaches PostgreSQL and gets refused there instead:

Fedora’s initdb writes ident for TCP connections from localhost, which asks an identd on the client for the OS user name. Nothing answers that on Fedora, and pgAdmin connects as apache anyway, so ident can never match postgres. Switch the two host all all lines to password authentication:
sudo vim /var/lib/pgsql/data/pg_hba.conf
Change ident to scram-sha-256 on the IPv4 and IPv6 host all all lines. With comments stripped, the file reads:
local all all peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
local replication all peer
host replication all 127.0.0.1/32 ident
host replication all ::1/128 ident
The local ... peer line stays, so sudo -u postgres psql keeps working without a password. Reload PostgreSQL and test the exact path pgAdmin uses, a password login over TCP:
sudo systemctl reload postgresql
PGPASSWORD='Db-Pass-2345' psql -h 127.0.0.1 -U postgres -tAc "select current_user, inet_server_addr();"
A row back means the password and the auth method agree:
postgres|127.0.0.1
scram-sha-256 works here because PostgreSQL’s password_encryption is already scram-sha-256, so the hash stored by ALTER USER is the right type. Save the server in pgAdmin again and it connects, opening the activity dashboard for the new node:

Sessions, transactions and block I/O graphs start filling within a few seconds. For a remote PostgreSQL server the same two fixes apply on that server’s side: a host line for the pgAdmin box’s address in its pg_hba.conf, and listen_addresses set beyond localhost.
Why the pgAdmin repo fails on Fedora 45
If you followed pgadmin.org’s instructions on Fedora 45, you hit one or more of these errors, in this order, because each fix only exposes the next one:
- NOKEY on the repo RPM
- 404 on the Fedora 45 repodata
- HTTP 500 after pinning the Fedora 44 tree
They are recorded here with the exact messages so your search for the error lands on the cause. Our Fedora 45 third-party repo 404 guide tracks the same release gap for Docker, CUDA and other vendors, and the pattern is the same: a vendor tree that lags behind the Fedora release.
package pgadmin4-fedora-repo does not verify: NOKEY
Fedora 45 enforces package signature checking by default (the Enforcing signature checking by default change), so RPM refuses a package whose signing key is not in your keyring. Fedora 44 only checked digests and carried on with a warning. pgadmin.org’s instructions never import the key before rpm -i, so on Fedora 45 the repo RPM never installs and you see this.
warning: /var/tmp/rpm-tmp.oiasbK: Header OpenPGP V4 RSA/SHA256 signature, key ID 8881b2a8210976f2: NOKEY
package pgadmin4-fedora-repo-2-1.noarch does not verify: Header OpenPGP V4 RSA/SHA256 signature, key ID 8881b2a8210976f2: NOKEY
You can see the difference on each release with rpm --eval '%_pkgverify_level', which printed all on our Fedora 45 VM and digest on the Fedora 44 one. Importing pgAdmin’s signing key first lets the repo RPM install. It only moves you to the next error, though, so do not stop here.
sudo rpm --import https://www.pgadmin.org/static/packages_pgadmin_org.pub
Once imported, the key shows up in rpm -q gpg-pubkey as the pgAdmin package signing key, and its fingerprint ends in 8881b2a8210976f2, matching the ID in the error. Rerun the rpm -i line and it installs /etc/yum.repos.d/pgadmin4.repo with gpgcheck=1 and repo_gpgcheck=1, so the signature problem is solved for good. The repository it points at is the next problem.
Status code: 404 for fedora-45-x86_64/repodata/repomd.xml
The repo file uses fedora-$releasever-$basearch, and the server has no Fedora 45 directory. On 3 November 2026 the tree listing held only fedora-43-x86_64 and fedora-44-x86_64, and pgadmin.org’s own support table lists Fedora 43 and 44:
>>> Status code: 404 for https://ftp.postgresql.org/pub/pgadmin/pgadmin4/yum/fedora/fedora-45-x86_64/repodata/repomd.xml (IP: 203.0.113.10) - https://ftp.postgresql.org/pub/pgadmin/pgadmin4/yum/fedora/fedora-45-x86_64/repodata/repomd.xml
>>> Usable URL not found
Repositories loaded.
Failed to resolve the transaction:
No match for argument: pgadmin4-web
The tree was still missing when we tested against the stable Fedora 45 repositories, so check whether it has appeared before you settle on a route. A 200 means pgAdmin has published Fedora 45 builds.
curl -s -o /dev/null -w '%{http_code}\n' https://ftp.postgresql.org/pub/pgadmin/pgadmin4/yum/fedora/fedora-45-x86_64/repodata/repomd.xml
Our check printed 404. Until it prints 200, stay on Fedora’s package, and when it does flip you can move over by removing pgadmin4 and pgadmin4-httpd first, because the two builds both write their Apache config to /etc/httpd/conf.d/pgadmin4.conf.
HTTP 500 and “No module named ‘flask'” after pinning the Fedora 44 tree
The usual 404 workaround, pointing baseurl at fedora-44, installs cleanly on Fedora 45. dnf even pulls python3.14 to satisfy pgadmin4-server, and setup-web.sh reports success. The login page then returns HTTP 500, and Apache’s error log shows why:
AH00489: Apache/2.4.69 (Fedora Linux) mod_wsgi/5.0.2 Python/3.15 configured -- resuming normal operations
mod_wsgi (pid=1711): Failed to exec Python script file '/usr/pgadmin4/web/pgAdmin4.wsgi'.
File "/usr/pgadmin4/web/pgadmin/__init__.py", line 24, in <module>
from flask import Flask, Response, abort, request, current_app, g, \\
ModuleNotFoundError: No module named 'flask'
mod_wsgi embeds one Python interpreter, and on Fedora 45 that’s Python 3.15. The vendor’s virtual environment in /usr/pgadmin4/venv was built for Python 3.14, so its site-packages directory is invisible to the 3.15 interpreter and Flask can’t be imported. Fedora 45 has no Python 3.14 build of mod_wsgi to swap in, which makes this a dead end for web mode rather than a config tweak. Remove the vendor packages and the repo, then follow the Fedora 45 section above:
sudo dnf remove pgadmin4-web pgadmin4-server pgadmin4-fedora-repo python3.14 python3.14-libs
sudo rm -rf /var/lib/pgadmin /var/log/pgadmin /usr/pgadmin4
sudo setsebool -P httpd_can_network_connect off
sudo setsebool -P httpd_can_network_connect_db off
sudo setsebool -P httpd_tmp_exec off
Read the dnf transaction before you answer y, because removing python3.14 also removes anything else on the box that depends on it. The rm clears the vendor’s config database and leftover files so Fedora’s package recreates /var/lib/pgadmin with its own ownership. The boolean resets matter because the vendor’s setup-web.sh turned all three on, and they survive the package removal; we reset the two network booleans on our VM before testing the Fedora route, turned on only the database boolean again when pgAdmin asked for it, and switched httpd_tmp_exec off at the end with no effect on pgAdmin.
That is the whole decision in one line: on Fedora 45 run Fedora’s pgadmin4 with pgadmin4-httpd and httpd, and on Fedora 44 the vendor repository is still the newer choice. Once pgAdmin is up, our Fedora 45 post-install checklist covers the rest of the box.