Fix PostgreSQL "Permission denied" on /var/lib/pgsql in OpenShift
— ny_wk

You deploy PostgreSQL on OpenShift or Kubernetes and the pod dies instantly with:
mkdir: cannot create directory '/var/lib/pgsql/data/userdata': Permission denied
The database can't write to its own data directory. This is almost always a storage permissions problem between the container's user and the mounted volume — not a Postgres bug. Here's how to fix it.
Why it happens
Two common causes:
- SELinux labels: on SELinux-enforcing hosts, the mounted volume directory isn't labeled for container access, so the kernel blocks the write.
- UID/GID mismatch: OpenShift runs containers with a random, non-root user by default. If the volume is owned by root (or a fixed UID) and isn't group-writable for the pod's group, the Postgres process can't create its directory.
Fix 1 — Set the right SELinux label (host volumes)
If you're using a host-path/local volume on an SELinux host, relabel it so containers may use it:
chcon -Rt svirt_sandbox_file_t /path/to/volume
(Adjust the path and type to your environment.) This tells SELinux the directory is fair game for container processes.
Fix 2 — Fix ownership with fsGroup (the Kubernetes-native way)
Better than chasing host permissions: let the platform set group ownership of the volume to the pod's group using a securityContext:
- Set
securityContext.fsGroupon the pod so the mounted volume is group-owned by that GID and group-writable. - OpenShift's default restricted SCC assigns a random UID but a known fsGroup — aligning the volume's group with it lets the non-root Postgres user write.
Fix 3 — Use a supported PostgreSQL image / StorageClass
The Red Hat/OpenShift PostgreSQL images are built to run as an arbitrary non-root UID and handle these permissions correctly. Use the official image from the catalog, and a dynamic StorageClass (which provisions volumes with proper permissions) rather than a hand-mounted host path.
Key takeaways
- The error is a volume permissions issue, not a Postgres fault.
- On SELinux hosts, relabel host volumes:
chcon -Rt svirt_sandbox_file_t /path. - The clean fix is securityContext.fsGroup so the volume is writable by the pod's group.
- Prefer the official OpenShift Postgres image + a dynamic StorageClass to avoid this entirely.
Frequently asked questions
Why does it run as a random user?
OpenShift's restricted security context assigns an arbitrary non-root UID for safety, so images must not assume they run as a fixed user or root.
Should I just run the pod as root?
No — that defeats OpenShift's security model and often isn't allowed. Fix the volume permissions/fsGroup instead.
What does chcon do here?
It sets the SELinux type label on the directory so container processes are permitted to access it.
fsGroup or SELinux — which should I use?
For dynamically provisioned volumes, fsGroup is the right, portable fix. chcon is for host-path volumes on SELinux nodes.
Match the volume's permissions to the non-root user OpenShift gives you — via fsGroup (or the right SELinux label) — and PostgreSQL starts cleanly.