What's New with Monitoring in PostgreSQL 19

saisrirampur1 pts0 comments

. -->

What's New with Monitoring in PostgreSQL 19 | ClickHouse<br>Skip to content

Open searchOpen region selectorEnglish<br>Japanese<br>Korean<br>Chinese<br>French<br>Spanish<br>Portuguese<br>Arabic

49.3kSign inGet Started

->Scroll to top<br>BackBlog<br>Engineering<br>Copy pageCopied!More actionsView as Markdown Open this page in Markdown<br>Open in ChatGPT Ask questions about this page<br>Open in Claude Ask questions about this page<br>Open in v0 Ask questions about this page

What's New with Monitoring in PostgreSQL 19

Gülçin Yıldırım Jelínek<br>Aug 18, 2026 · 11 minutes read

PostgreSQL 19 is around the corner, and I will be talking about observability improvements at the upcoming PostgreSQL Conference Europe. I am also co-organizing the PostgreSQL Observability Summit as part of Community Events Day on the last day of the conference, Friday, October 23. So, I thought this was a good time to organize my thoughts in a blog post.

Disclaimer: PostgreSQL 19 is still in beta as I write this, so some of the details below may change before the final release. The release notes will be the final word once 19.0 goes GA.

With that out of the way, let's look at the PostgreSQL 19 monitoring and observability improvements that I find most useful and interesting.

Lock contention is now visible by default #

log_lock_waits controls whether to log a message when a session waits longer than deadlock_timeout (1 second by default) to acquire a lock. Checking for deadlock is relatively expensive, so you’re advised to set an amount of time to wait before that check happens, ideally longer than your regular transaction time. This is the relationship between deadlock_timeout and log_lock_waits (Robert Haas even suggested separating the two). In short, enabling log_lock_waits provides a cheap lock contention detector for Postgres, yet it defaulted to off up until now.

PostgreSQL 19 flips the default to on (commit 2aac62be8, Laurenz Albe). I love the reasoning in the commit message:

If someone is stuck behind a lock for more than a second, that is almost always a problem that is worth a log entry.

Different log verbosity per process type #

log_min_messages has always been a single global knob. If you wanted DEBUG2 output from the checkpointer, you got DEBUG2 from everything and good luck finding the line you care about.

Starting with PostgreSQL 19, log_min_messages accepts a comma-separated list of process type:level pairs, plus one mandatory level that applies to every process type not listed. A bare level is still valid, so the old syntax keeps working.

1-- DEBUG2 for the checkpointer, DEBUG1 for autovacuum, WARNING for everything else<br>2ALTER SYSTEM SET log_min_messages = 'warning, checkpointer:debug2, autovacuum:debug1';Copy command

The recognized process types are archiver, autovacuum, backend, bgworker, bgwriter, checkpointer, checksums, ioworker, postmaster, slotsyncworker, startup, syslogger, walreceiver, walsender, walsummarizer and walwriter. Note that autovacuum covers both the launcher and the workers.

Separate logging for autoanalyze #

Until now, log_autovacuum_min_duration controlled log output for both VACUUM and ANALYZE runs by autovacuum. These are very different operations: autoanalyze runs are typically much shorter, so a threshold tuned to catch slow vacuums silently discards almost all ANALYZE activity.

PostgreSQL 19 adds log_autoanalyze_min_duration, which controls log output for ANALYZE. log_autovacuum_min_duration now only controls VACUUM logging. Both default to 10min, accept 0 (log everything) and -1 (disable). You can also set per-table overrides:

1-- For this table log every autoanalyze, regardless of the global setting<br>2ALTER TABLE events SET (log_autoanalyze_min_duration = 0);Copy command

Upgrade notes: If your tooling parses autovacuum logs, remember that after the upgrade log_autovacuum_min_duration alone no longer reports analyze runs. And if you’re displaying log parameters in a UI, consider making log_autoanalyze_min_duration visible as well.

WAL full-page write bytes to VACUUM and ANALYZE logging #

Full-page images are often the dominant part of WAL volume and VACUUM generates plenty of them. If you’re not familiar with why, I’ll try to explain a bit. The first time a page is modified after a checkpoint, Postgres writes the entire 8kB page into the WAL instead of just the small change so crash recovery never has to trust a possibly torn page on disk. That means one tiny update of a 50-byte row can produce ~8kB of WAL if it happens to be the first touch of that page since the last checkpoint. VACUUM crawls through and dirties lots of cold pages, so it triggers plenty of these, which is why vacuuming a big, cold table can generate far more WAL than the amount of data it actually changed.

Postgres reported full-page image counts (wal_fpi) but not their size, so if you wanted the actual bytes, you had to dig through WAL with pg_waldump or pg_walinspect.

PostgreSQL 19 adds a new wal_fpi_bytes counter, added through a...

postgresql page autovacuum open vacuum analyze

Related Articles