You’ve run into a classic system administrator puzzle.
You need to stop your PostgreSQL database, so you type the standard command: sudo systemctl stop postgresql-14.
The command finishes without any errors, but when you check the running processes, the database is still there, humming along.
What’s going on? Is systemctl broken?
The answer is no. The problem isn’t the tool, but a misunderstanding of what it controls.
The key to solving this mystery lies in knowing that PostgreSQL can be run in two fundamentally different ways, and your shutdown command must match the way it was started.
Table of Contents
Two Ways PostgreSQL Can Run
PostgreSQL, like many server applications, doesn’t have just one way to be launched. Understanding these two methods is crucial.
- As a System Service (Managed by
systemctl) This is the most common and recommended method for production environments. When you install PostgreSQL using a package manager (likeyumorapt), it usually sets up asystemdservice file. This allows the operating system’s service manager to handle the database automatically. It starts PostgreSQL on boot, manages its process, and handles logging in a standardized way. When you usesystemctl startorstop, you are communicating with this management layer. - As a Manual Process (Managed by
pg_ctl) PostgreSQL also comes with its own command-line utility,pg_ctl, designed for direct control of a database cluster. An administrator can use it to manually start, stop, or restart a PostgreSQL server by pointing it directly to a data directory. This method is often used for development, testing, running multiple PostgreSQL versions on one machine, or in environments that don’t usesystemd.
The trick is that systemctl only knows about the database instances it started. If a PostgreSQL process was launched manually with pg_ctl, the system’s service manager is completely unaware of its existence and cannot control it.
How to Identify the Running Instance
To figure out what’s going on, you need to play detective. The ps command is your best tool for investigating the running PostgreSQL processes.
First, get a list of all PostgreSQL processes and their Process IDs (PIDs):
See also: Mastering the Linux Command Line — Your Complete Free Training Guide
ps aux | grep postgres
This might give you a long list, but it will confirm the database is running. To get more specific details, pick a PID from the list and inspect it closely. For example, if you see a process with PID 3041469, run:
ps -o pid,ppid,cmd -p 3041469
This command shows the Process ID (pid), the Parent Process ID (ppid), and the full command (cmd) that launched it.
Let’s look at an example output:
You might see something like this:
postgres 286672 1 0 2023 ? 05:50:23 /usr/pgsql-14/bin/postgres -D /pgdata/default -c config_file=/pgdata/default/postgresql.conf
or
postgres 3041469 1 0 03:02 ? 00:00:00 /usr/pgsql-14/bin/postmaster -D /pgdata/default -c config_file=/pgdata/default/postgresql.conf
The first process is manually started. The second is systemd-managed. Only the systemd-managed instance responds to systemctl stop.
Once you’ve identified how your PostgreSQL instance was started, stopping it becomes simple.
How to Safely Stop a Systemd-Managed Instance
If your investigation revealed the process has a Parent PID of 1, systemctl is the correct tool. You can also confirm the data directory that systemctl expects to manage with this command:
systemctl cat postgresql-14 | grep -i datadir
This helps you verify you are targeting the correct instance.
To stop it, use the standard command:
sudo systemctl stop postgresql-14
How to Safely Stop a Manually-Started Instance
If the process was started manually, you must use pg_ctl. The most important piece of information you need is the data directory, which you can find in the output of the ps command (using the -D flag).
To stop this instance, run:
pg_ctl -D /pgdata/default stop
Note: You may need to run this as the postgres user.
This sends a clean shutdown signal directly to the database process that systemctl couldn’t see.
Key Takeaway
The next time you find that systemctl stop isn’t working for PostgreSQL, don’t get frustrated. Remember this core principle: the command used to stop the service must match the method used to start it.




