
PostgreSQL stores all database files, including tables, indexes, WAL segments, and configuration state, under a single data directory. On Ubuntu, the default location is /var/lib/postgresql/<version>/main. This directory lives on the system disk by default, which means a growing database competes for space with the operating system, logs, and other services. When that disk fills up, PostgreSQL will stop accepting writes. Moving the data directory to a dedicated volume resolves the space constraint without touching your database schema, users, or application configuration.
By the end of this tutorial, your PostgreSQL instance will be reading and writing data from the new location, the original directory will be archived as a rollback point, and you will have verified the change from inside a live psql session.
Follow these operational rules to minimize downtime and startup failures:
SHOW data_directory; before moving anything.rsync instead of cp to preserve permissions and metadata.700) and ensure ownership by postgres:postgres.data_directory in the correct versioned postgresql.conf file.postgresql.conf.Moving the PostgreSQL data directory is usually about operational constraints: disk capacity, storage isolation, and planned infrastructure changes.
Common reasons include:
If the move is part of a larger data protection or migration plan, validate your storage change alongside your replication strategy. For context on configuring and validating replication behavior, see How To Set Up Logical Replication with PostgreSQL 10 on Ubuntu 18.04.
You need the following before you start moving data.
sudo privileges on Ubuntu.data_directory and validate after the move. If you are setting up PostgreSQL, see How To Install and Use PostgreSQL on Ubuntu.rsync installed on the server.Ubuntu 20.04 reached End of Life in April 2025. If you are running 20.04, plan an upgrade to a supported Ubuntu release. See the Ubuntu release cycle.
Confirm the data directory PostgreSQL is currently using, then validate that the path exists on the filesystem.
To verify the authoritative data directory, connect to PostgreSQL as the postgres user and run SHOW data_directory;.
- sudo -u postgres psql
psql (PostgreSQL <postgresql_version>)
Type "help" for help.
postgres=#
SHOW data_directory;
data_directory
-----------------------------
/var/lib/postgresql/<postgresql_version>/main
(1 row)
Close the prompt:
\q
Now confirm the directory that SHOW data_directory; reported actually exists and has the expected ownership and mode.
sudo -u postgres ls -la /var/lib/postgresql/<postgresql_version>/main
total 16
drwx------ 19 postgres postgres 4096 Mar 25 10:12 .
drwxr-xr-x 3 postgres postgres 4096 Mar 25 09:58 ..
drwx------ 2 postgres postgres 4096 Mar 25 10:12 base
drwx------ 2 postgres postgres 4096 Mar 25 10:12 global
drwx------ 2 postgres postgres 4096 Mar 25 10:12 pg_wal
Verifying from inside psql is authoritative because it reflects the value PostgreSQL uses at runtime after configuration is loaded. Checking the filesystem path alone can mislead you if data_directory was changed earlier.
Stop PostgreSQL before you copy, rename, or remove any data files.
Run:
sudo systemctl stop postgresql
Then verify the service state:
sudo systemctl status postgresql
● postgresql.service - PostgreSQL RDBMS
Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Wed 2026-03-25 10:45:12 UTC; 10s ago
Process: 12345 ExecStart=/bin/true (code=exited, status=0/SUCCESS)
Main PID: 12345 (code=exited, status=0/SUCCESS)
Never copy or move the data directory while PostgreSQL is running. Data corruption can result.
Create the new directory and set ownership and permissions so PostgreSQL can read and write it.
Create the directory under your new mount point.
sudo mkdir -p <volume_mount_point>/postgresql
Example mount point path:
sudo mkdir -p /mnt/volume_nyc1_01/postgresql
The new directory must be owned by postgres:postgres with mode 700 before you copy any data. PostgreSQL checks these values at startup and will refuse to start if the data directory is accessible to any other user or group.
sudo chown -R postgres:postgres <volume_mount_point>/postgresql
sudo chmod 700 <volume_mount_point>/postgresql
After running both commands, confirm the permissions were applied before continuing.
Verify ownership on the mount point directory:
ls -la /mnt/volume_nyc1_01/
total 24
drwxr-xr-x 3 root root 4096 Mar 25 10:30 .
drwxr-xr-x 18 root root 4096 Mar 25 10:01 ..
drwx------ 3 postgres postgres 4096 Mar 25 10:30 postgresql
Copy the existing PostgreSQL data directory tree to the new location using rsync.
sudo rsync -av /var/lib/postgresql <volume_mount_point>
building file list ... done
postgresql/
postgresql/<postgresql_version>/
postgresql/<postgresql_version>/main/
postgresql/<postgresql_version>/main/PG_VERSION
...
sent <bytes_sent> bytes received <bytes_received> bytes total size <total_size>
These are the key rsync behaviors used in the move.
| Flag | Purpose | What Breaks Without It |
|---|---|---|
-a |
Archive mode preserves permissions, ownership, symlinks, and timestamps | PostgreSQL may refuse to start if permissions or ownership do not match what it expects |
-v |
Verbose output so you can follow progress | You have less visibility, which increases the chance you miss a copy failure |
| No trailing slash on the source path | Copies the directory itself, not only its contents | The destination layout can differ from what data_directory points to |
Prefer rsync over cp when permission fidelity matters. For PostgreSQL, permission fidelity is always required because PostgreSQL enforces security expectations at startup.
Verify that the main directory for your PostgreSQL major version exists at the new location.
sudo -u postgres ls -la <volume_mount_point>/postgresql/<postgresql_version>/main
total 16
drwx------ 19 postgres postgres 4096 Mar 25 10:55 .
drwxr-xr-x 3 postgres postgres 4096 Mar 25 10:50 ..
drwx------ 2 postgres postgres 4096 Mar 25 10:55 base
drwx------ 2 postgres postgres 4096 Mar 25 10:55 global
drwx------ 2 postgres postgres 4096 Mar 25 10:55 pg_wal
You should see standard PostgreSQL subdirectories inside main. If you do not, stop and confirm your rsync destination and whether you accidentally used a trailing slash.
Update data_directory in the versioned postgresql.conf so PostgreSQL starts from the new path.
Edit the file at:
/etc/postgresql/<postgresql_version>/main/postgresql.conf
Open it with nano:
sudo nano /etc/postgresql/<postgresql_version>/main/postgresql.conf
Find and update the data_directory directive. Replace the old path with the new one.
data_directory = '/var/lib/postgresql/<postgresql_version>/main'
Find the line that begins with data_directory and replace the path with your new location. Use Ctrl+W in nano to search for data_directory if the file is long.
data_directory = '<volume_mount_point>/postgresql/<postgresql_version>/main'
Save and exit nano with CTRL + X, Y, then ENTER.
Start PostgreSQL again and confirm that SHOW data_directory; reports the new location.
Start the service:
sudo systemctl start postgresql
Verify systemd status:
sudo systemctl status postgresql
● postgresql.service - PostgreSQL RDBMS
Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; vendor preset: enabled)
Active: active (exited) since Wed 2026-03-25 10:57:40 UTC; 2s ago
Process: 12398 ExecStart=/bin/true (code=exited, status=0/SUCCESS)
Main PID: 12398 (code=exited, status=0/SUCCESS)
The active (exited) state on postgresql.service is normal, because it is a wrapper unit. The actual database process runs under the versioned service such as postgresql@<postgresql_version>-main.service.
Verify with psql:
sudo -u postgres psql -c "SHOW data_directory;"
data_directory
-----------------------------
<volume_mount_point>/postgresql/<postgresql_version>/main
(1 row)
After you verify the server is using the new directory, keep the old directory as a rollback option before deleting it.
Rename the original directory to a backup name:
sudo mv /var/lib/postgresql/<postgresql_version>/main /var/lib/postgresql/<postgresql_version>/main.bak
Do not delete the old directory immediately. Run PostgreSQL from the new location for several days, including at least one backup and restore cycle, before removing the backup. If you use Barman for backups, see How To Back Up, Restore, and Migrate PostgreSQL Databases with Barman on CentOS 7.
After you confirm normal operation and a backup and restore test, remove the backup directory:
sudo rm -Rf /var/lib/postgresql/<postgresql_version>/main.bak
This command is destructive and cannot be undone.
You can move the data directory while avoiding direct changes to data_directory by using symbolic links or bind mounts.
| Method | Complexity | Reversibility | Recommended Use Case |
|---|---|---|---|
rsync-based move with postgresql.conf edit |
Medium | High, because you can restore the old data_directory value |
When you want explicit configuration and clear rollback |
| Using a symbolic link | Low to Medium | Medium | When you want to keep postgresql.conf unchanged but can tolerate indirection |
| Using a bind mount | Medium | High | When you want the mapping to survive reboots without editing postgresql.conf |
Use a symbolic link when you want the original path to point to your new directory.
Example commands:
sudo mv /var/lib/postgresql/<postgresql_version>/main /new/path
sudo ln -s /new/path /var/lib/postgresql/<postgresql_version>/main
Symlinks add an indirection layer that can complicate pg_upgrade and some backup tooling.
Use a bind mount when you want a reboot-persistent mapping for the original path.
Add an /etc/fstab entry in this pattern:
<volume_mount_point>/postgresql/<postgresql_version>/main /var/lib/postgresql/<postgresql_version>/main none bind 0 0
Verify the mount works immediately:
sudo mount -a
(no output on success)
If sudo mount -a returns an error, check dmesg or journalctl -xe to identify the filesystem or fstab parsing failure.
The fstab entry must be in place before the PostgreSQL service starts at boot, otherwise PostgreSQL will fail to find its data directory after a reboot.
Use postgresql.conf edits when you want explicit, reviewable configuration and easy rollback. Use symbolic links only if your operations, upgrades, and backups can handle the extra indirection. Use bind mounts when you want the original path to continue working across reboots without relying on config edits.
If the move fails, rollback by restoring the original data_directory setting, then restart PostgreSQL.
Open postgresql.conf and revert data_directory back to the original path.
sudo nano /etc/postgresql/<postgresql_version>/main/postgresql.conf
Set:
data_directory = '/var/lib/postgresql/<postgresql_version>/main'
Save and exit nano with CTRL + X, Y, then ENTER.
Restart PostgreSQL and verify the active data directory:
sudo systemctl restart postgresql
sudo systemctl status postgresql
● postgresql.service - PostgreSQL RDBMS
Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; vendor preset: enabled)
Active: active (exited) since Wed 2026-03-25 11:10:22 UTC; 2s ago
Process: 12450 ExecStart=/bin/true (code=exited, status=0/SUCCESS)
Main PID: 12450 (code=exited, status=0/SUCCESS)
sudo -u postgres psql -c "SHOW data_directory;"
data_directory
-----------------------------
/var/lib/postgresql/<postgresql_version>/main
(1 row)
If PostgreSQL fails to start, check logs under /var/log/postgresql/ for the specific error.
The three most common root causes of post-move startup failure are:
postgres:postgres).data_directory path in postgresql.conf.This procedure works across supported Ubuntu releases, with only the version-specific paths changing.
| Ubuntu Version | Default PostgreSQL Version | Default Data Directory | Config File Path |
|---|---|---|---|
| 20.04 | 12 | /var/lib/postgresql/12/main |
/etc/postgresql/12/main/postgresql.conf |
| 22.04 | 14 | /var/lib/postgresql/14/main |
/etc/postgresql/14/main/postgresql.conf |
| 24.04 | 16 | /var/lib/postgresql/16/main |
/etc/postgresql/16/main/postgresql.conf |
The procedure in this article applies to all of them. The only differences are the version number in the paths and the config file location.
Ubuntu 20.04 is EOL. If you are running 20.04, plan your upgrade before your next maintenance window.
Q: How do I find where PostgreSQL is currently storing data on Ubuntu?
A: Connect to PostgreSQL using psql and run SHOW data_directory;. This returns the active path PostgreSQL is using, which is the authoritative source regardless of what is set in configuration files.
Q: Why use rsync instead of cp to move the PostgreSQL data directory?
A: rsync with the -a flag preserves file permissions, ownership, symbolic links, and timestamps. A standard cp command without explicit flags can silently drop these attributes, which causes PostgreSQL to refuse to start due to permission errors.
Q: What permissions does the new PostgreSQL data directory need?
A: The directory must be owned by the postgres user and postgres group. The permission mode should be 700. PostgreSQL will refuse to start if the data directory is accessible to other users.
Q: Where is the postgresql.conf file located on Ubuntu?
A: The default location is /etc/postgresql/<version>/main/postgresql.conf. For PostgreSQL 12 on Ubuntu 20.04, the full path is /etc/postgresql/12/main/postgresql.conf.
Q: Can I use a symbolic link instead of editing postgresql.conf?
A: Yes. You can move the data to the new location and create a symbolic link at the original path pointing to the new directory. This avoids editing the configuration file but adds an indirection layer that can complicate troubleshooting and upgrades.
Q: Is it safe to delete the old data directory after the move?
A: Do not delete the old directory immediately. Rename it first and run PostgreSQL from the new location for several days. Once you have confirmed normal operation, including backups and restores, you can safely remove the old directory.
Q: Does this procedure work on Ubuntu 22.04 with PostgreSQL 14?
A: The procedure is the same. The difference is the default data directory path, which is /var/lib/postgresql/14/main on Ubuntu 22.04 with PostgreSQL 14, and the configuration file path, which is /etc/postgresql/14/main/postgresql.conf.
Q: What should I do if PostgreSQL fails to start after moving the data directory?
A: Check the PostgreSQL logs at /var/log/postgresql/ for the specific error. The most common causes are incorrect ownership on the new directory, a typo in the data_directory path in postgresql.conf, or the new filesystem mount not being available at boot time. Restore the original data_directory value in postgresql.conf and restart to roll back.
Moving your PostgreSQL data directory on Ubuntu is a safe and routine operation when you follow a careful process. Always double-check data directory paths, permission settings, and backup practices to avoid issues. For more details on PostgreSQL administration or Ubuntu system management, see the DigitalOcean Community. Consider upgrading your Ubuntu release to stay secure and supported for future database maintenance.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Thanks for the useful article. One question though - the last action item is to remove the remainings of the old db by executing: “rm -Rf /var/lib/postgresql/12/main.bak”
But what about the left overs in the /var/lib/postgresql folder itself? can it also be deleted safely? (I can see it was already recreated in the block storage)
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
Sign up and get $200 in credit for your first 60 days with DigitalOcean.*
*This promotional offer applies to new accounts only.