Fixing PostgreSQL Stale postmaster.pid Lock File
The Problem
PostgreSQL service shows an error status in Homebrew:
❯ brew services list
Name Status User File
postgresql@17 error 1 user ~/Library/LaunchAgents/[email protected]
The Investigation
Checking the Logs
The PostgreSQL log revealed the issue:
❯ tail -50 /opt/homebrew/var/log/[email protected]
2026-01-15 10:57:27.984 PST [49027] FATAL: lock file "postmaster.pid" already exists
2026-01-15 10:57:27.984 PST [49027] HINT: Is another postmaster (PID 732) running in data directory "/opt/homebrew/var/postgresql@17"?
PostgreSQL was failing to start because a postmaster.pid lock file already existed, claiming PID 732 was using it.
Checking the Lock File
❯ cat /opt/homebrew/var/postgresql@17/postmaster.pid
732
/opt/homebrew/var/postgresql@17
1764184024
5432
/tmp
localhost
21922676 65536
stopping
The lock file contained:
- PID 732 - the process ID that supposedly owns the lock
- Port 5432 - the PostgreSQL port
- Status: “stopping” - PostgreSQL was mid-shutdown when something went wrong
Checking if PID 732 is Actually PostgreSQL
❯ ps aux | grep -E "^.* 732 "
user 732 0.0 0.1 435406032 59968 ?? S Tue10AM 0:11.34 /System/Library/PrivateFrameworks/IMCore.framework/imagent.app/Contents/MacOS/imagent
PID 732 is macOS’s iMessage daemon (imagent), not PostgreSQL!
Root Cause
- PostgreSQL was running with PID 732
- The system was shut down or PostgreSQL crashed while in “stopping” state
- The
postmaster.pidlock file was not cleaned up - After reboot, macOS assigned PID 732 to a different process (
imagent) - PostgreSQL refuses to start because the lock file claims PID 732 is still using the data directory
- PostgreSQL doesn’t verify if PID 732 is actually a postgres process
The Solution
Remove the stale lock file and restart PostgreSQL:
rm /opt/homebrew/var/postgresql@17/postmaster.pid
brew services restart postgresql@17
Understanding postmaster.pid
The postmaster.pid file serves several purposes:
- Prevents multiple instances - Ensures only one PostgreSQL server uses a data directory
- Stores connection info - Contains port number and socket directory for clients
- Enables clean shutdown - Used by
pg_ctl stopto find the running server
Lock File Format
<PID>
<Data Directory>
<Postmaster Start Timestamp>
<Port>
<Unix Socket Directory>
<Listen Addresses>
<Shared Memory Key> <Shared Memory Size>
<Status>
When Lock Files Become Stale
- System crash or power loss
kill -9on the postgres process- PostgreSQL crash during shutdown
- Container/VM termination without graceful shutdown
Prevention
-
Always shut down PostgreSQL gracefully:
brew services stop postgresql@17 -
Before system shutdown, ensure PostgreSQL is stopped
-
If PostgreSQL crashes, check for and remove stale lock files before restarting
Safety Note
Before removing postmaster.pid, always verify that no PostgreSQL process is actually running:
# Check for any postgres processes
pgrep -l postgres
# Or more thoroughly
ps aux | grep postgres | grep -v grep
Only remove the lock file if no PostgreSQL processes are found. Removing it while PostgreSQL is running can cause data corruption.