Fix PostgreSQL database locks and service failures on Debian 12 caused by full pg_log disk space. Learn to clear logs, free space, and prevent recurrence.
When your PostgreSQL database suddenly becomes unresponsive, applications fail to connect, or the entire web application ecosystem grinds to a halt, one of the most insidious culprits can be a full disk. Specifically, an overgrowth of PostgreSQL's transaction logs or pg_log files can consume all available space, leading to critical database failures, service unresponsiveness, and "lockfile" errors as PostgreSQL struggles to write essential operational data. This guide provides a highly technical, step-by-step resolution for this common issue on Debian 12 (Bookworm) systems.
Symptom & Error Signature
Users typically experience one or more of the following symptoms:
- Web applications reporting database connection errors (e.g., "could not connect to server: Connection refused", "FATAL: remaining connection slots are reserved for non-replication superuser connections").
- The PostgreSQL service (often
[email protected]or similar) is reported asfailedorinactivebysystemctl. - Attempts to start or restart PostgreSQL fail immediately.
- System logs (
journalctl) show errors related to disk I/O or inability to write.
Here are typical error messages you might encounter:
From journalctl -u postgresql (or journalctl -u [email protected] for specific versions):
systemd[1]: [email protected]: Start request repeated too quickly.
systemd[1]: [email protected]: Failed with result 'exit-code'.
systemd[1]: Failed to start PostgreSQL Cluster 15-main.
...
postgresql[12345]: 2024-06-25 10:30:00.123 UTC [12345] LOG: could not write lock file "/var/run/postgresql/.s.PGSQL.5432.lock": No space left on device
postgresql[12345]: 2024-06-25 10:30:00.123 UTC [12345] FATAL: could not create lock file "/var/run/postgresql/.s.PGSQL.5432.lock": No space left on device
postgresql[12345]: 2024-06-25 10:30:00.123 UTC [12345] LOG: database system is shut down
From dmesg (kernel messages, indicating disk I/O issues):
[123456.789012] EXT4-fs (sda1): write access unavailable, fs is full
[123456.789013] EXT4-fs (sda1): Remounting filesystem read-only
From df -h (showing disk usage):
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 50G 50G 0 100% /
udev 10M 0 10M 0% /dev
tmpfs 7.8G 1.2M 7.8G 1% /run
Root Cause Analysis
The root cause of this issue is typically a filesystem reaching 100% capacity on the partition where PostgreSQL stores its data and/or log files. This commonly happens on the root partition (/) if /var is not a separate mount, or on a dedicated /var partition.
Here's a breakdown of why this leads to the observed symptoms:
- Excessive Log Growth: PostgreSQL, by default, writes detailed logs to files within a directory like
/var/log/postgresql/or within the data directory itself (/var/lib/postgresql/<version>/main/log/). Without proper log rotation (e.g., vialogrotate), these log files can grow indefinitely, consuming gigabytes or even terabytes of disk space over time. - Lack of Free Space: Once the filesystem reaches 100% utilization, the operating system can no longer write any new data to that disk.
- PostgreSQL's Inability to Operate: PostgreSQL requires free disk space for several critical operations:
- * Writing Log Files: It cannot log new events, leading to internal errors.
- * Writing Transaction Logs (WAL): Crucial for data integrity and recovery. While WAL segments are usually pre-allocated, operational temporary files and checkpoints might require space.
- * Creating Lock Files: When PostgreSQL starts, it creates a lock file (e.g.,
/var/run/postgresql/.s.PGSQL.5432.lock) to prevent multiple instances from running on the same port. If it cannot create this file, it fails to start. - * Temporary Files and Caching: Queries that require large sorts or joins might create temporary files on disk. If these cannot be written, queries will fail.
- Service Failure: The inability to write lock files or perform other critical disk operations prevents the PostgreSQL server from starting or causes it to shut down gracefully (or crash) to prevent data corruption.
systemdwill then report the service as failed.
Step-by-Step Resolution
Follow these steps carefully to recover your PostgreSQL service and prevent future occurrences.
1. Verify Disk Space and Identify Culprit
First, confirm that your disk is indeed full and identify which directory is consuming the most space.
- Check overall disk usage:
-
`bash - df -h
-
` - Look for a partition (often
/or/var) showing 100%Use%.
- Identify large directories:
- Navigate to the suspected full partition and use
duto find the largest directories. Start broad and narrow down. -
`bash - sudo du -h /var/log | sort -rh | head -n 10
- sudo du -h /var/lib/postgresql | sort -rh | head -n 10
-
` - You're likely to see
/var/log/postgresql/or a subdirectory within/var/lib/postgresql/consuming significant space. For example: -
` - 50G /var/log/postgresql
- 48G /var/log/postgresql/postgresql-15-main.log.1
-
`
2. Stop PostgreSQL Service
Before manipulating PostgreSQL's log files or data directory, it is critical to stop the service to prevent data corruption.
[!WARNING] Do NOT proceed to delete files if PostgreSQL is still running, especially not within its data directory (
/var/lib/postgresql). This can lead to irreversible data loss or corruption.
sudo systemctl stop postgresql
# Or for a specific version:
sudo systemctl stop [email protected]
Verify the service is stopped:
`bash
sudo systemctl status postgresql
`
It should show Active: inactive (dead).
3. Clear Excessive pg_log Files
Once the service is stopped, you can safely remove old log files.
- Navigate to the PostgreSQL log directory:
- For Debian, this is typically
/var/log/postgresql/. -
`bash - cd /var/log/postgresql/
-
`
- List files and confirm their size:
-
`bash - ls -lh
-
` - This will show you the massive log files, usually named
postgresql-<version>-main.logor similar, possibly with suffixes like.1,.gz, etc.
- Delete old log files:
- Start by deleting the oldest and largest log files to free up space. You might need to delete iteratively until you have enough free space to restart the database.
[!IMPORTANT] > Do not delete the current log file (
postgresql-<version>-main.log) or files still being written to (though this is less likely if the service is stopped). Focus on.1,.2,.gzfiles. > > Be cautious withrm -rf. Always verify the directory and files before execution.
To delete log files older than, say, 7 days:
`bash
sudo find . -name "postgresql--main.log." -mtime +7 -exec rm {} ;
`
To delete all but the most recent 2-3 log files (be careful with this, adjust head -n -3 to suit):
`bash
# List files sorted by modification time (oldest first)
ls -t postgresql--main.log. | tail -n +4 | xargs sudo rm -v
# The above command keeps the 3 newest logs. Adjust +4 to keep N-1 logs.
# E.g., tail -n +2 keeps 1 newest log.
# To delete all but the current one and the most recent rotated one:
# sudo rm postgresql--main.log.2 postgresql--main.log.3
`
If you're desperate for space and can afford to lose older logs for recovery:
`bash
sudo rm postgresql--main.log.
`
- Verify free space:
-
`bash - df -h
-
` - You should now see some available space. Aim for at least 1-2GB free to allow the database to start and operate normally.
4. Restart PostgreSQL Service
With disk space freed, attempt to restart the database service.
sudo systemctl start postgresql
# Or for a specific version:
sudo systemctl start [email protected]
5. Verify Database Operation
Check the status of the service and confirm your applications can connect.
- Check service status:
-
`bash - sudo systemctl status postgresql
-
` - It should now show
Active: active (running).
- Check logs for errors:
-
`bash - sudo journalctl -u postgresql -f
-
` - Look for
LOG: database system is ready to accept connections.
- Test application connectivity:
- Access your web application or connect via
psql: -
`bash - sudo -u postgres psql
-
` - If you get a
psqlprompt, the database is running. Typeqto exit.
6. Implement Log Rotation (Long-Term Fix)
To prevent this issue from recurring, configure logrotate for PostgreSQL. Debian's postgresql-common package usually sets up a basic logrotate configuration, but it might be overridden or misconfigured.
- Inspect existing logrotate configuration:
- Check
/etc/logrotate.d/postgresql-commonor/etc/logrotate.d/postgresql. -
`bash - sudo cat /etc/logrotate.d/postgresql-common
-
` - A typical configuration might look like this:
-
` - /var/log/postgresql/*.log {
- daily
- missingok
- rotate 7
- compress
- delaycompress
- notifempty
- create 0640 postgres adm
- su postgres adm
- postrotate
- # Find the PIDs of running postgresql clusters and send them a SIGHUP
- if [ -e /etc/postgresql/15/main/postgresql.conf ] ; then
- pg_ctlcluster 15 main reload > /dev/null || true
- fi
- endscript
- }
-
`
- Adjust
logrotatesettings if necessary: - *
rotate 7: Keeps 7 rotated logs. Adjust this number (e.g.,rotate 14for two weeks) based on your disk space and retention needs. - *
daily,weekly,monthly: How often logs are rotated.dailyis generally good for busy systems. - *
compress: Compresses old log files. Highly recommended. - *
size 100M: You can addsize <bytes>(e.g.,size 100M) to force rotation when a log file reaches a certain size, regardless of thedaily/weeklysetting. This is very effective for high-volume logs. - > [!IMPORTANT]
- > If you make changes, ensure they are compatible with existing logrotate options. A common issue is a missing
postrotatescript to signal PostgreSQL to reopen log files. Without it, PostgreSQL might continue writing to the old (renamed) log file. Thepg_ctlcluster ... reloadcommand correctly handles this.
- Manually test
logrotate: -
`bash - sudo logrotate -f /etc/logrotate.d/postgresql-common
-
` - This forces a rotation immediately. Check
/var/log/postgresql/afterwards to confirm new log files are created and old ones are rotated/compressed.
7. Configure PostgreSQL Logging (Proactive)
Fine-tuning PostgreSQL's logging behavior in postgresql.conf can also help manage disk space.
- Edit
postgresql.conf: -
`bash - sudo nano /etc/postgresql/15/main/postgresql.conf
-
`
- Review and adjust these parameters:
-
log_destination: Set tostderrorcsvlog(if you want structured logs).stderris standard for syslog/journal. - *
logging_collector = on: (Default) This sends log messages to files managed by PostgreSQL itself. Ifoff, logs go to syslog, which then needs syslog's own rotation. For/var/log/postgresqlmanagement, keep iton. - *
logdirectory = 'pglog': (Relative to data directory) or/var/log/postgresql(absolute path). - *
logfilename = 'postgresql-%Y-%m-%d%H%M%S.log': This creates unique log files per start time, whichlogrotatecan then manage. - *
logrotationage = 1d: Rotates logs daily. This works in conjunction withlogrotate. -
logrotationsize = 0: Disables size-based rotation by PostgreSQL itself iflogrotateis handling it. Set a value (e.g.,100MB) if you want PostgreSQL to rotate before* logrotate. It's often better to letlogrotatehandle it consistently. - *
logminduration_statement = 1000: Logs all statements taking longer than 1 second (1000ms). Adjust this value to0to log all statements (VERY VERBOSE, use with caution on production), or increase it to5000(5 seconds) to reduce log volume. - *
log_statement = 'none': Logs no statements. Can beddl,mod,all.noneis recommended for most production environments unless debugging. - *
log_checkpoints = on: Logs each checkpoint. Useful for performance monitoring. - *
log_connections = on: Logs successful client connections. - *
log_disconnections = on: Logs end of client sessions.
[!IMPORTANT] > Setting
logrotationageorlogrotationsizedirectly inpostgresql.confprovides a fallback or additional rotation layer. However,logrotateis generally preferred for system-wide log management. Ensure yourpostgresql.confsettings don't conflict or create redundant files. Iflogrotateis robustly configured, you can setlogrotationage = 0andlogrotationsize = 0inpostgresql.confto letlogrotatehandle it exclusively.
- Restart PostgreSQL after
postgresql.confchanges: -
`bash - sudo systemctl restart postgresql
-
`
8. Consider Dedicated Disk/Partition (Advanced)
For high-traffic production databases, it's often prudent to separate PostgreSQL's data and log directories onto dedicated partitions or even separate physical disks. This isolates I/O and prevents a full log partition from impacting the entire system or vice-versa.
- Mount a new disk/partition:
- Create a new filesystem and mount it, e.g., to
/mnt/pgdataor/mnt/pglogs. - Edit
/etc/fstabto ensure it mounts automatically on boot.
- Move PostgreSQL data or logs:
- * Moving logs: Change
logdirectoryinpostgresql.confto point to the new location (e.g.,/mnt/pglogs). Remember to create the directory and set correct permissions (chown postgres:postgres /mnt/pg_logs). - * Moving data directory: This is more involved. You would stop PostgreSQL, copy
/var/lib/postgresql/to the new location (e.g.,/mnt/pgdata), updatedatadirectoryinpostgresql.conf, and potentially update the systemd service file orpg_ctlclusterconfiguration.
This comprehensive approach will not only resolve the immediate disk space and lockfile issues but also establish robust logging and maintenance practices to prevent recurrence.
Leave a Reply