How to fix fixing permissions on existing directory in PostgreSQL

PostgreSQLBEGINNERHIGHUpdated Dec 29, 2025· 402 views

PostgreSQL "fixing permissions on existing directory" error occurs when initdb cannot change permissions on the PGDATA directory to the required security settings. This happens due to directory ownership issues, insufficient privileges, or containerized environments with volume mount problems. Fix by ensuring the postgres user owns the directory and has appropriate permissions before running initdb.

Quick fix

Fixes fixing permissions on existing directory

# Stop PostgreSQL service
sudo systemctl stop postgresql
# or
sudo service postgresql stop
# or for manual installations:
sudo killall postgres
  1. Stop any running PostgreSQL server
  2. Identify the correct PGDATA directory location
  3. Create the data directory if it does not exist
  4. Verify the postgres user exists
postgresql — error
# Stop PostgreSQL service
sudo systemctl stop postgresql
# or
sudo service postgresql stop
# or for manual installations:
sudo killall postgres
fixing permissions on existing directory

What this error means

PostgreSQL "fixing permissions on existing directory" is an initialization error that occurs when the `initdb` command attempts to secure the data directory by setting strict permissions (0700 for the postgres user only). This error appears during PostgreSQL cluster initialization when initdb cannot modify directory permissions due to filesystem restrictions or ownership issues. The full error message typically reads: "initdb: could not change permissions of directory \"/var/lib/postgresql/data\": Operation not permitted". This happens because PostgreSQL requires exclusive control of the data directory for security reasons. All database files contain sensitive data, and PostgreSQL restricts access to only the operating system user running the database daemon (typically the "postgres" user). The initialization process expects to: 1. Create the data directory (or use an existing one) 2. Set ownership to the postgres user 3. Set permissions to 0700 (read/write/execute for owner only) When any of these steps fails, initdb cannot proceed. This commonly occurs in: - Docker containers where volume mounts inherit host filesystem restrictions - Kubernetes environments with NFS persistent volumes - Systems where the postgres user lacks write permissions to parent directories - Windows installations where permission inheritance is different - Cases where the data directory is owned by root or another user

Typical symptoms

  • initdb command fails with "Operation not permitted" when trying to change directory permissions
  • Full error message: "initdb: could not change permissions of directory ... Operation not permitted"
  • PostgreSQL fails to start immediately after installation
  • In Docker/containers: PostgreSQL initialization fails even though directories exist
  • Volume mount in Docker/Kubernetes shows permission denied errors
  • Cannot initialize a fresh PostgreSQL cluster in an existing directory
  • NFS-backed persistent volumes in Kubernetes fail cluster initialization
  • Ansible/Terraform/Infrastructure-as-Code PostgreSQL provisioning fails at initdb stage
  • Using sudo or running initdb with elevated privileges still fails

Common causes

  1. Data directory is owned by root or another user instead of the postgres system user
  2. Parent directories have restrictive permissions that prevent the postgres user from managing subdirectories
  3. In Docker: volume mount inherited restrictive permissions from the host filesystem
  4. In Kubernetes: NFS persistent volume has restrictive default permissions blocking ownership changes
  5. Filesystem is mounted read-only or with nodev/nosuid options preventing permission changes
  6. The postgres user lacks write permission to parent directories needed to create/modify the data directory
  7. SELinux or AppArmor security policies restrict permission modifications by the postgres user
  8. Initdb is run with inappropriate privileges (as root or with sudo) preventing permission setting
  9. Attempting to initialize in a directory that already contains files with restrictive permissions

How to fix "fixing permissions on existing directory"

1Stop any running PostgreSQL server

Before modifying directory permissions and ownership, ensure no PostgreSQL process is using the data directory.

bash
# Stop PostgreSQL service
sudo systemctl stop postgresql
# or
sudo service postgresql stop
# or for manual installations:
sudo killall postgres

Verify the process is stopped:

bash
ps aux | grep postgres

No postgres processes should appear in the output (grep itself may appear but not the actual postgres daemon).

2Identify the correct PGDATA directory location

Determine which directory PostgreSQL should use as its data directory. Check your installation configuration or intended setup.

bash
# Common locations:
/var/lib/postgresql/data      # Linux package installation
/usr/local/pgsql/data         # Source installation
/var/pgsql                    # BSD/macOS
$PGDATA                       # Custom location (check environment)

# If you are not sure, check the PostgreSQL configuration file:
sudo grep "^data_directory" /etc/postgresql/*/main/postgresql.conf

For a fresh installation, you may need to create the directory first. Identify the correct parent directory where PGDATA should live.

3Create the data directory if it does not exist

If the directory does not exist yet, create it with appropriate permissions from the start to avoid permission errors.

bash
# Create the data directory (example: /var/lib/postgresql/data)
sudo mkdir -p /var/lib/postgresql/data

Ensure the parent directory (/var/lib/postgresql) exists and is writable by root. If creating in a custom location, verify the parent directory exists first:

bash
# Verify parent exists
ls -ld /var/lib/postgresql
4Verify the postgres user exists

PostgreSQL requires a dedicated system user named "postgres" (or a custom user if configured). Verify this user exists on your system.

bash
# Check if postgres user exists
id postgres

# If not found, create it (Linux):
sudo useradd --system --home /var/lib/postgresql --shell /bin/bash postgres

# Or on some systems:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin postgres

Note the output of id postgres — it will show the UID, GID, and groups. The postgres user is typically UID 106-120 and GID 112-130.

5Change ownership of the data directory to the postgres user

Recursively change ownership of the entire data directory and its contents to the postgres user. This is the most common fix for this error.

bash
# Change ownership to postgres user and group
sudo chown -R postgres:postgres /var/lib/postgresql/data

# Verify the change:
ls -ld /var/lib/postgresql/data
# Output should show: drwx------ postgres postgres ...

If the directory is new and empty, this operation completes instantly. If it contains existing PostgreSQL files, chown processes all files recursively. For very large directories, this may take time.

6Set correct permissions on the data directory

PostgreSQL requires the data directory to be readable, writable, and executable only by the postgres user (mode 0700). Set these permissions explicitly.

bash
# Set directory permissions to 0700 (rwx-----)
sudo chmod 700 /var/lib/postgresql/data

# Verify the permissions:
ls -ld /var/lib/postgresql/data
# Output should show: drwx------ postgres postgres ...

The "700" means:
- Owner (postgres): read (4) + write (2) + execute (1) = 7
- Group: no permissions = 0
- Others: no permissions = 0

PostgreSQL will refuse to start if the directory has any permissions beyond 0700 for security reasons.

7For Docker/Kubernetes: adjust volume mount permissions

If using Docker or Kubernetes persistent volumes, you may need to configure volume mount options to allow the postgres user to manage permissions.

Docker Compose example:

yaml
services:
  postgres:
    image: postgres:latest
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_INITDB_ARGS: "-c shared_buffers=256MB"
    # Add initdb script to fix permissions:
    command: |
      bash -c "
      chown -R 999:999 /var/lib/postgresql/data && \
      chmod 700 /var/lib/postgresql/data && \
      docker-entrypoint.sh postgres
      "

volumes:
  postgres_data:

Kubernetes StatefulSet example:

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: standard
  resources:
    requests:
      storage: 10Gi
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
spec:
  serviceName: postgres
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
      - name: postgres
        image: postgres:latest
        volumeMounts:
        - name: postgres-storage
          mountPath: /var/lib/postgresql/data
        # Pre-init to fix permissions
        securityContext:
          runAsUser: 999  # postgres user in the container
        # Ensure volume is writable before initialization
      initContainers:
      - name: fix-permissions
        image: busybox
        command:
        - sh
        - -c
        - chmod 700 /var/lib/postgresql/data; chown 999:999 /var/lib/postgresql/data
        volumeMounts:
        - name: postgres-storage
          mountPath: /var/lib/postgresql/data
      volumes:
      - name: postgres-storage
        persistentVolumeClaim:
          claimName: postgres-pvc

For NFS volumes, you may also need to configure the NFS export with no_root_squash or adjust the UID mapping.

8Clear the data directory if it contains orphaned files

If the data directory contains old or corrupted files from a previous failed initialization, initdb may fail even after fixing ownership. Clear the directory and start fresh.

bash
# WARNING: This deletes all data in the directory!
# Only do this if the directory contains no important data or you have backups.

sudo -u postgres rm -rf /var/lib/postgresql/data/*

# Verify it is empty:
sudo ls -la /var/lib/postgresql/data/

After clearing, proceed to initialize PostgreSQL with initdb.

9Initialize the PostgreSQL cluster with initdb

Now that the directory ownership and permissions are correct, run initdb to initialize the cluster. Do NOT use sudo — run initdb as the postgres user.

bash
# Switch to postgres user and initialize
sudo -u postgres initdb -D /var/lib/postgresql/data

# Or if postgres user has a shell:
su - postgres
initdb -D /var/lib/postgresql/data
exit

You should see output like:

bash
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "en_US.UTF-8".
...
Success. You can now start the database server using:
    pg_ctl -D /var/lib/postgresql/data -l logfile start

If initdb succeeds, the error is resolved.

10Start PostgreSQL and verify initialization

After successful initdb, start the PostgreSQL service to verify the cluster is usable.

bash
# Start PostgreSQL service
sudo systemctl start postgresql
# or
sudo service postgresql start
# or for manual installations:
sudo -u postgres pg_ctl -D /var/lib/postgresql/data -l /var/log/postgresql/postgresql.log start

Verify the service is running:

bash
sudo systemctl status postgresql

# Or check if the postgres process is listening:
ps aux | grep postgres
netstat -an | grep 5432  # Default PostgreSQL port

Then connect to verify the database is accessible:

bash
sudo -u postgres psql -c "SELECT version();"

If you see the PostgreSQL version output, the initialization and startup succeeded.

Advanced notes

This error is distinct from regular permission denied errors because it occurs specifically during cluster initialization (initdb) rather than during normal operation. The initdb command is particularly strict about directory permissions because it sets up the foundational security of the entire PostgreSQL installation.

Under the hood, initdb calls the chown() and chmod() system calls. If these calls fail with EPERM (Operation not permitted), initdb cannot proceed. This can happen if:
1. The current user (even root) cannot change ownership on certain filesystems
2. The filesystem is mounted with restrictive options (nodev, nosuid, noacl)
3. The kernel or filesystem driver blocks permission operations

On SELinux systems, the postgres_t context must have permission to manage the directory. Run getenforce to check if SELinux is enforcing policies. Temporarily disable with sudo setenforce 0 (or disable permanently in /etc/selinux/config) to test if SELinux is the culprit.

For Windows PostgreSQL installations, this error manifests differently since Windows uses ACLs instead of Unix permissions. Run the PostgreSQL installer as Administrator and choose a directory outside "Program Files" (which has UAC restrictions). If you see permission errors after installation, try "runas /user:Administrator cmd" and re-run the installer.

In containerized environments (Docker/Kubernetes), the entry point script usually handles permission fixing. If initialization still fails:
- Check the UID of the postgres user inside the container (might be 999 instead of standard values)
- Ensure the volume mount is not mounted read-only
- Check for SELinux contexts on the host interfering with the container filesystem
- Test with explicit chown and chmod commands in an initContainer (Kubernetes) or entrypoint (Docker)

For multi-node PostgreSQL setups (replication), fix permissions on the primary server first, then replicate the directory to secondaries only after the primary has completed initialization. Do not attempt to initialize on secondaries—use pg_basebackup or physical replication from the primary.

Frequently asked questions

What does "fixing permissions on existing directory" mean?
PostgreSQL "fixing permissions on existing directory" is an initialization error that occurs when the initdb command attempts to secure the data directory by setting strict permissions (0700 for the postgres user only). This error appears during PostgreSQL cluster initialization when initdb cannot modify directory permissions due to filesystem restrictions or ownership issues. The full error message typically reads: "initdb: could not change permissions of directory \"/var/lib/postgresql/data\": Operation not permitted".
How do I fix "fixing permissions on existing directory"?
PostgreSQL "fixing permissions on existing directory" error occurs when initdb cannot change permissions on the PGDATA directory to the required security settings. This happens due to directory ownership issues, insufficient privileges, or containerized environments with volume mount problems. Fix by ensuring the postgres user owns the directory and has appropriate permissions before running initdb.
What causes "fixing permissions on existing directory"?
Data directory is owned by root or another user instead of the postgres system user Parent directories have restrictive permissions that prevent the postgres user from managing subdirectories In Docker: volume mount inherited restrictive permissions from the host filesystem
Is the "fixing permissions on existing directory" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading