initdb: error: could not change permissions of directory "/mnt/c/...": Operation not permitted
— PostgreSQL in WSL was asked to keep its data on the Windows drive, and that mount cannot
hold Linux owners or permissions. Put the data directory on the Linux file system, under
/var/lib/postgresql, and initdb succeeds.
On Ubuntu that means leaving out the -d option of pg_createcluster:
the cluster then goes to /var/lib/postgresql/16/<name>, inside the
distribution's own ext4 disk. The step that fails is a permission change, so the directory
has to move, or the mount has to change, as shown further down.
The error
$ sudo pg_createcluster 16 wincl -d /mnt/c/.../fix5-pgdata2
Creating new PostgreSQL cluster 16/wincl ...
/usr/lib/postgresql/16/bin/initdb -D /mnt/c/.../fix5-pgdata2 --auth-local peer --auth-host scram-sha-256 --no-instructions
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 "C.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".
Data page checksums are disabled.
fixing permissions on existing directory /mnt/c/.../fix5-pgdata2 ... initdb: error: could not change permissions of directory "/mnt/c/.../fix5-pgdata2": Operation not permitted
Error: initdb failed
Running initdb -D on a directory that does not exist yet gets one step further
and stops at could not change permissions of "/mnt/c/.../postgresql.conf". A
cluster copied onto /mnt/c and started from there fails with
FATAL: data directory "/mnt/c/..." has wrong ownership instead.
Why it happens
/mnt/c is not a Linux file system. WSL2 mounts the Windows drive with drvfs over
the 9p protocol: mount shows C:\ on /mnt/c type 9p (rw,noatime,aname=drvfs;...;uid=1000;gid=1000
and stat -f reports v9fs. Without the metadata mount
option, the drive does not keep a Linux owner or mode: every folder in this test showed the
default user as its owner and rwxrwxrwx as its permissions, whatever
chown and chmod said.
PostgreSQL wants its data directory owned by the user the server runs as and closed to
everyone else, so initdb's first step on an existing directory is to set its mode. The
postgres user is not the owner the mount reports, so the change is refused.
Root fares no better: sudo chown postgres:postgres and
sudo chmod 700 on the directory both returned success, and ls -ld
afterwards still showed drwxrwxrwx 1 dev dev.
The fix
$ sudo pg_createcluster 16 dev -p 15482 --start
$ pg_lsclusters
Ver Cluster Port Status Owner Data directory Log file
16 dev 15482 online postgres /var/lib/postgresql/16/dev /var/log/postgresql/postgresql-16-dev.log
16 main 5432 down postgres /var/lib/postgresql/16/main /var/log/postgresql/postgresql-16-main.log
$ sudo -u postgres psql -p 15482 -c "CREATE TABLE note (id int PRIMARY KEY, author text);" -c "INSERT INTO note VALUES (1, 'Maria Garcia');" -c "SELECT * FROM note;"
CREATE TABLE
INSERT 0 1
id | author
----+--------------
1 | Maria Garcia
(1 row)
The same initdb lines ran to syncing data to disk ... ok this time. Port 15482
is this test's own; the cluster the package created at install time, 16/main,
already lives under /var/lib/postgresql and is enough for most work. The data
is still on your PC, inside the distribution's virtual disk.
If the data really must sit on C:, mount the drive with the metadata option.
Here sudo mount -t drvfs C: /mnt/cmeta -o metadata,uid=1000,gid=1000 let initdb
finish and the server start, but pgbench -i -s 10 took 39.01 s to load a
million rows there against 0.76 s on ext4, and the default pgbench load ran 553
transactions per second against 798.
How it was reproduced
A throwaway distribution, wsl --install Ubuntu-24.04 --name fix5-pg --no-launch
(Ubuntu 24.04.5, WSL 2.7.10, kernel 6.18.33.2), with a fictional default user and
apt-get install postgresql, which gave PostgreSQL 16.15
(16.15-0ubuntu0.24.04.1). Three attempts on /mnt/c failed: initdb creating the
directory, pg_createcluster -d, and a directory made first and handed to
postgres. Paths are shortened to /mnt/c/...; nothing else in the output changed.
The names fix5-pg and dev are this test's own, and the distribution was unregistered
afterwards.
Frequently asked
- Can I keep PostgreSQL data on the C: drive in WSL?
- Only if the drive is mounted with the drvfs metadata option, which lets it store Linux owners and modes. In this test initdb then finished and the server started, but loading a million pgbench rows took 39 seconds there against under one second on the Linux file system. Keep the data under /var/lib/postgresql.
- Why does chmod not work on /mnt/c in WSL?
- Without the metadata mount option the Windows drive does not keep a Linux owner or mode, so files and folders there show your default user and rwxrwxrwx. A chmod by another user, such as postgres, is refused with Operation not permitted, and one run with sudo reports success and changes nothing.
- How do I fix 'data directory has wrong ownership' for PostgreSQL in WSL?
- The server was pointed at a data directory on /mnt/c, where every file appears to belong to your default user. Copy the directory to the Linux file system, for example under /var/lib/postgresql, run chown -R postgres:postgres and chmod 700 on it, and start the server from there.
More decoded errors in the Fixes category. For why projects belong on the Linux side of WSL in general, with build times measured on both, see WSL for .NET work.