<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/all-your-gucs-in-a-row-min-wal-size-qq6biabdi" -->

---
title: All Your GUCs in a Row: min_wal_size | daily.dev
description: A deep technical breakdown of PostgreSQL's min_wal_size parameter explains that, contrary to its name, it does not retain WAL for standbys or point-in-time...
canonical: https://daily.dev/posts/all-your-gucs-in-a-row-min-wal-size-qq6biabdi
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: All Your GUCs in a Row: min_wal_size | daily.dev
og:description: A deep technical breakdown of PostgreSQL's min_wal_size parameter explains that, contrary to its name, it does not retain WAL for standbys or point-in-time...
og:url: https://daily.dev/posts/all-your-gucs-in-a-row-min-wal-size-qq6biabdi
og:image: https://api.daily.dev/og/posts/qQ6BIAbdI.png
og:image:alt: All Your GUCs in a Row: min_wal_size
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# All Your GUCs in a Row: min_wal_size

**[Planet PostgreSQL](https://daily.dev/sources/planet-postgresql)** · 7 min read · 1 upvotes · 0 comments

## Summary

A deep technical breakdown of PostgreSQL's min_wal_size parameter explains that, contrary to its name, it does not retain WAL for standbys or point-in-time recovery—it is purely a floor on how far the WAL pool can shrink during recycling. The piece walks through how recycling and the max_wal_size autotuner interact, shows via benchmarks that running out of pool forces backends to zero-fill and fsync new 16MB segments while holding WALWriteLock (measured at 21ms per segment, causing p99.9 latency to double), and covers edge cases like wal_recycle=off silently disabling the floor, disk-full behavior, pg_rewind overhead, and a long-standing bug where the enforced minimum is checked only at postmaster start. It closes with practical sizing guidance: set min_wal_size equal to max_wal_size when disk was provisioned for that ceiling.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://postgr.es/p/9wX>

## Questions this post answers

### Does min_wal_size in PostgreSQL control how much WAL is retained for a standby?

No, min_wal_size only sets a floor on how far the WAL pool in pg_wal is allowed to shrink during recycling; it keeps no WAL that any process could actually read. The renamed segments sitting in pg_wal below that floor are stale, pre-zeroed files waiting to be overwritten. To retain WAL for a replica, use wal_keep_size or a replication slot instead.

_Anyone sizing WAL retention for standbys can cross-check PostgreSQL GUC behavior like this on daily.dev before it causes an outage._

### What happens in PostgreSQL when WAL writes run past the end of the pre-allocated WAL pool?

A backend process has to create the next 16MB segment itself: zero-filling it, calling fsync, and renaming it, all while holding WALWriteLock, blocking every other commit behind it. Measurements showed this takes about 21ms per segment on a fast disk (128ms on a throttled 125MB/s network volume), doubling p99.9 commit latency during the burst, though median and average throughput barely change.

_Teams debugging commit latency spikes during WAL bursts can dig into root causes like this via daily.dev._

### What is the real minimum allowed value for PostgreSQL's min_wal_size parameter?

The real minimum is two WAL segments, not the value of 2 shown in pg_settings, which is expressed in megabytes and misleading. With 64MB segments the effective minimum is 128MB, above the 80MB compiled-in default, which is why initdb writes an explicit min_wal_size line into postgresql.conf for non-default segment sizes. This limit is checked only when the postmaster reads the control file at startup, not at SET time.

_Operators tuning PostgreSQL WAL segment sizing can verify edge-case limits like this through daily.dev before a restart fails._

## Similar posts on daily.dev

- [All Your GUCs in a Row: max\_slot\_wal\_keep\_size](https://daily.dev/posts/all-your-gucs-in-a-row-max-slot-wal-keep-size-puebij5nc) · Planet PostgreSQL · 3 upvotes · 0 comments
- [All Your GUCs in a Row: max\_wal\_senders](https://daily.dev/posts/all-your-gucs-in-a-row-max-wal-senders-kl8rlurbg) · Planet PostgreSQL · 0 upvotes · 0 comments
- [All Your GUCs in a Row: full\_page\_writes](https://daily.dev/posts/all-your-gucs-in-a-row-full-page-writes-iwrk5j2gz) · Planet PostgreSQL · 0 upvotes · 0 comments
- [PostgreSQL Recovery Internals](https://daily.dev/posts/postgresql-recovery-internals-fyfrz2lny) · CYBERTEC PostgreSQL · 3 upvotes · 0 comments

---

Tags: [#postgresql](https://daily.dev/tags/postgresql)

[View this post on daily.dev](https://daily.dev/posts/all-your-gucs-in-a-row-min-wal-size-qq6biabdi)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"All Your GUCs in a Row: min_wal_size","url":"https://daily.dev/posts/all-your-gucs-in-a-row-min-wal-size-qq6biabdi","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/all-your-gucs-in-a-row-min-wal-size-qq6biabdi"},"datePublished":"2026-10-04T01:02:12.607Z","dateModified":"2026-10-04T01:02:42.308Z","description":"A deep technical breakdown of PostgreSQL's min_wal_size parameter explains that, contrary to its name, it does not retain WAL for standbys or point-in-time...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/f6c82f9989fadf971d25be5f67fa83fa?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/f6c82f9989fadf971d25be5f67fa83fa?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Planet PostgreSQL","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Planet PostgreSQL","logo":"https://media.daily.dev/image/upload/logos/placeholder.jpg","url":"https://daily.dev/sources/planet-postgresql"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/all-your-gucs-in-a-row-min-wal-size-qq6biabdi","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":1},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"postgresql","timeRequired":"PT7M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Planet PostgreSQL","item":"https://daily.dev/sources/planet-postgresql"},{"@type":"ListItem","position":3,"name":"All Your GUCs in a Row: min_wal_size"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/all-your-gucs-in-a-row-min-wal-size-qq6biabdi#faq","mainEntity":[{"@type":"Question","name":"Does min_wal_size in PostgreSQL control how much WAL is retained for a standby?","acceptedAnswer":{"@type":"Answer","text":"No, min_wal_size only sets a floor on how far the WAL pool in pg_wal is allowed to shrink during recycling; it keeps no WAL that any process could actually read. The renamed segments sitting in pg_wal below that floor are stale, pre-zeroed files waiting to be overwritten. To retain WAL for a replica, use wal_keep_size or a replication slot instead. Anyone sizing WAL retention for standbys can cross-check PostgreSQL GUC behavior like this on daily.dev before it causes an outage."}},{"@type":"Question","name":"What happens in PostgreSQL when WAL writes run past the end of the pre-allocated WAL pool?","acceptedAnswer":{"@type":"Answer","text":"A backend process has to create the next 16MB segment itself: zero-filling it, calling fsync, and renaming it, all while holding WALWriteLock, blocking every other commit behind it. Measurements showed this takes about 21ms per segment on a fast disk (128ms on a throttled 125MB/s network volume), doubling p99.9 commit latency during the burst, though median and average throughput barely change. Teams debugging commit latency spikes during WAL bursts can dig into root causes like this via daily.dev."}},{"@type":"Question","name":"What is the real minimum allowed value for PostgreSQL's min_wal_size parameter?","acceptedAnswer":{"@type":"Answer","text":"The real minimum is two WAL segments, not the value of 2 shown in pg_settings, which is expressed in megabytes and misleading. With 64MB segments the effective minimum is 128MB, above the 80MB compiled-in default, which is why initdb writes an explicit min_wal_size line into postgresql.conf for non-default segment sizes. This limit is checked only when the postmaster reads the control file at startup, not at SET time. Operators tuning PostgreSQL WAL segment sizing can verify edge-case limits like this through daily.dev before a restart fails."}}]}
```

