PostgreSQL 18 had its first release candidate on September 4, 2025, and went GA three weeks later. As I write this, on September 14, 2026, PostgreSQL 19 has no release candidate date. It has a fourth beta scheduled for September 24, a commit freeze for that beta on September 19, and a stated goal of GA “by the end of October.” In the last three weeks it has lost two of the features that headlined every “what’s new in 19” post written since June, including mine. On August 31, Bruce Momjian wrote on -hackers that “it feels we are in an unprecedented situation here.” A week later, Joshua Drake proposed moving the release to spring 2027. Nobody took him up on it. Nobody laughed, either.
This is not a “PostgreSQL is falling apart” post. The project reverts things late every year; the PostgreSQL 11 cycle had a scariest-patch tournament of its own, and WAIT FOR took a decade and three reverts to land. But 19 is different in degree.
Where things stand
| PostgreSQL 18 | PostgreSQL 19 | |
|---|---|---|
| Feature freeze | April 8, 2025 | April 8, 2026 |
| Beta 1 | May 8, 2025 | June 4, 2026 |
| Beta 3 | August 14, 2025 | August 13, 2026 |
| Beta 4 | none | September 24, 2026 |
| RC 1 | September 4, 2025 | TBD |
| GA | September 25, 2025 | “end of October” |
The open items page listed 37 open issues on September 1 and 23 as of its September 11 revision. Five of the 23 are REPACK, all owned by Álvaro Herrera; five more are UPDATE/DELETE FOR PORTION OF. The reversion hall of fame since August 25:
ALTER TABLE ... MERGE/SPLIT PARTITION: reverted August 26–27, “due to multiple design issues which are too late to address in this release cycle.”- SQL/PGQ property graphs: reverted September 7. 124 files, 15,859 deletions on master.
- RI fast-path batching: removed from
REL_19_STABLESeptember 10 by its own committer. GROUP BY ALL: reverted before beta 3.- Non-plain
pg_dumpalloutput formats: reverted before beta 2. - Provider-specific identifier casefolding and the postmaster
LC_COLLATEchange: reverted by Jeff Davis, one at a time, over the first two weeks of September. - The
CREATE SCHEMAsubcommand work: reverted by Tom Lane in the second week of September, because it changed the meaning of statements that 18 already accepts.
Still in the tree, and still arguing: REPACK (CONCURRENTLY), online data checksums, FOR PORTION OF, and the pg_get_*_ddl() functions. I’ll come back to each.
Eight features in five weeks
The proximate cause is visible in the commit log for the five weeks before feature freeze, the same five weeks that produced the 212 release-note items Bruce Momjian counted in April. REPACK landed March 10. pg_plan_advice landed March 12, after nearly slipping to v20. SQL/PGQ landed March 16. COPY TO ... FORMAT JSON landed March 20. FOR PORTION OF landed April 1. Online data checksums landed April 3. The pg_get_*_ddl() functions landed April 5. REPACK (CONCURRENTLY) landed April 6, two days before the freeze, and postgres_fdw statistics import landed on freeze day itself.
Last-minute commits are a PostgreSQL tradition, and no one should be shocked by them. What is different this time is what kind of features they were. These are not leaf features that can be pulled out with a scalpel. REPACK (CONCURRENTLY) is built on logical decoding. RI batching sat inside the trigger and subtransaction machinery. PGQ added a new relkind and new catalogs. FOR PORTION OF changes executor and trigger semantics for UPDATE and DELETE. When Momjian says that the project doesn’t know whether “their removal will effect other changes that were made assuming those feature existed,” that is the coupling he means, and it’s why every reversion in this list has been followed by a discussion of what else has to come out with it.
The REPACK (CONCURRENTLY) commit message deserves quoting, because it is quite candid about what was being committed:
There are some loose ends in this commit:
- concurrent repack needs its own replication slot in order to apply logical decoding, which are a scarce resource and easy to run out of.
- due to the way the historic snapshot is initially set up, only one REPACK process can be running at any one time on the whole system.
- there’s a danger of deadlocking (and thus abort) due to the lock upgrade required at the final phase.
These issues will be addressed in upcoming commits.
Some of them were. Item 2 was not; the prerequisite that would have fixed it (database-specific logical replication snapshots) was itself reverted as fundamentally flawed, per the summary Robert Haas posted in August, which is why the version of REPACK (CONCURRENTLY) that will ship, if it ships, is limited to one process per cluster. A feature committed forty hours before freeze with a numbered list of known design holes is a decision, and the rest of the summer was spent paying for it.
The scary patch contest
On August 25, Robert Haas posted a thread to -hackers titled “scary patch contest.” The first sentence: “I asked Claude to evaluate which v19 patches were the scariest based on the number and type of bugs fixed post-freeze. Results below, with a few particularly cutting remarks from the LLM edited out.” The list, with the LLM’s fix counts:
- RI fast-path FK checks and batching: about 16 fixes, “five distinct classes of incorrect FK enforcement,” and a transactional design “retrofitted post-freeze.”
REPACKandREPACK (CONCURRENTLY): 28 fixes, including data loss.- Online data checksums: about 25 fixes, “mostly state-machine holes.” Haas’s gloss: “A corruption-detection feature producing false positives is exactly the wrong failure mode.”
UPDATE/DELETE FOR PORTION OF: 17 fixes, three of them security.- SQL/PGQ: 17 fixes, “lower severity.”
postgres_fdwstatistics import: committed on freeze day, then 7 fixes for about one file of contrib code.
Haas’s own position: “I’m pretty scared about all of #1-#3 having a long tail of bugs that we haven’t found yet, in pretty critical areas.” Tom Lane replied that PGQ was the one that frightened him, because the fixes still under discussion needed catalog changes: “At this point I’d be willing to bet dinner that if we ship it in v19 there will be post-release bug discoveries that are unfixable until v20.” Daniel Gustafsson, who committed online checksums, replied to the whole thing with four words: “I’ll prepare a revert.”
Melanie Plageman, speaking for the Release Management Team, pushed back on that within the hour, and asked the question that I think is the real one:
One thing that I’m wondering is if the ease with which LLMs allow people to pressure test features means we are finding more bugs sooner than we have in the past.
Hold that thought.
Three weeks on, the results. At the start of September, Plageman told the PGQ thread that the RMT had “serious concerns about the number of design issues” and that “we feel it would be better to revert this in 19.” On September 3, Haas put the case on the record: PGQ checked its prerequisites at CREATE PROPERTY GRAPH time and then let you drop them, so ALTER TABLE v DROP CONSTRAINT v_pkey left a graph with no key and ALTER TABLE t2 DROP COLUMN b CASCADE turned a working GRAPH_TABLE query into a failing one. “To me, this class of problem seems completely unacceptable in a committed feature… There’s just a big design gap here, AFAICS, which is not the sort of thing we should be trying to plug after the initial commit.” Andres Freund added the locking problems: the rewriter read element tables without locks, and dropping a table belonging to a graph didn’t lock the graph at all. Peter Eisentraut’s reply: “Ok, let’s do it.” The revert landed September 7.
RI batching went on September 10. Amit Langote, who co-authored and committed it, removed the batching layer himself, keeping the per-row fast path. His reasoning, first in the proposal and then in the commit message, is the clearest statement of the problem with all of these: the code had “repeatedly had to address how a live batch of pending checks interacts with trigger-firing cycles, subtransactions, deferred constraints, and SET CONSTRAINTS,” and “failure to handle one of those cases can leave a buffered check unperformed, allowing a transaction to commit a permanent foreign key violation without reporting an error.” Haas has since asked, in public, whether the per-row fast path should stay in 19 either. As of this writing it has: one open item, a collation-mismatch bug fixed on September 10, and a cast-cache invalidation bug found while testing it that turned out to reach 18.6 as well.
FOR PORTION OF is the one currently on the table. Paul Jungwirth filed a fourteen-item index of defects on September 3 and has been landing fixes since; then on September 10 Andres Freund read the feature and opened on the acknowledged READ COMMITTED problem (concurrent updates to the same row producing lost updates), which he called unacceptable, followed by executor problems and, the next morning, seven more findings. Twenty minutes after that, Nathan Bossart, RMT hat on, asked Eisentraut and Jungwirth to respond. That is exactly the sequence that preceded the PGQ and batching reverts. Five FOR PORTION OF items are open, and the commit freeze for beta 4 is Saturday.
Online checksums is the strangest of the four. Gustafsson made the case for keeping it himself, with numbers (of 29 post-commit commits, 12 were bug fixes; “it’s by far the most complicated and ambitious thing I’ve ever built for Postgres”), and reported the last open item closed. Then Haas ran Claude over the patches and found a structural one: enabling checksums by walking the catalog never touches relation files orphaned by a crash before commit, so after any crash in the cluster’s history a base backup will fail checksum verification. Nobody has a fix. Tom Lane asked whether anything cleans up orphaned relation files; nothing does. Noah Misch found the wal_level=minimal case where replay can’t repair it either. That thread is where things stood on Friday.
pg_get_*_ddl() rounds out the set. Misch’s open item is titled “needs a redesign,” and when the RMT urged the authors to say whether the feature needs to be fixed or reverted, Misch closed the third option: “I don’t see ‘fixes’ addressing this thread as a whole, unless you plan to dispute the premise that the feature needs a redesign.” Andrew Dunstan, the committer, is not conceding: “To me it is beyond stupid that a postgresql server doesn’t have enough introspection to be able to produce the DDL for its own objects.” He’s right about that, and it doesn’t settle whether this implementation ships.
REPACK (CONCURRENTLY): the whole cycle in miniature
REPACK (CONCURRENTLY) deserves its own section, because it is the feature the release is being measured by and because everything that went wrong with 19 went wrong with it first.
It is pg_squeeze brought into core: copy the table under a share-update-exclusive lock, decode the concurrent changes through a logical replication slot, replay them into the copy, swap relfilenodes under a brief exclusive lock. Cybertec has shipped that design for years and Antonin Houska knows it better than anyone. That is not the same thing as the design being ready for src/backend/commands.
The sequence: committed April 6 with the loose-ends list above. Compressed TOAST corruption found and fixed before beta 1. On June 16, Houska posted a patch set for the next cycle whose first line is “REPACK (CONCURRENTLY) is not MVCC-safe,” with the fix explicitly described as a prototype he never expected to make 19. Cybertec’s own May blog post said they hoped it “will not have to be reverted before the PostgreSQL 19 release,” which is a sentence a sponsor does not write about a feature it feels good about. On August 27, Nathan Bossart opened seven separate REPACK threads in one afternoon, and Bharath Rupireddy an eighth: REPACK (ANALYZE) segfaulting inside a transaction block, REPACK (CONCURRENTLY) rewriting user_catalog_table relations, failing when the table owner lacks CONNECT, not checking the table access method, waiting forever when its decoding worker fails to start. On September 2, Thom Brown reported that a logical decoding session with include-rewrites set could be crashed by a concurrent REPACK, taking the whole cluster down with it; reachable by any user who can create a replication slot and run REPACK (CONCURRENTLY).
The response, between September 8 and 9, was to cut scope rather than fix: REPACK (CONCURRENTLY) now rejects non-heap access methods (because a table AM without logical decoding silently loses every row written during the rewrite), user catalog tables, and materialized views; REPACK (ANALYZE) is refused inside a transaction block, described in the commit as “a temporary stopgap.” The crash was fixed, though one of the two one-line fixes the report proposed was wrong and Houska had to correct it. Haas’s assessment on August 25 still stands: the feature “has been cut back in scope enough that I don’t think we would have accepted the feature originally if it had been subject to those limitations.” Five REPACK items remain open, including a new one from Misch on September 10, and Herrera owns all of them. It is still in the tree, and my guess is that it ships in 19 with a documentation page of caveats longer than the reference page. Use it the way you’d use a 1.0 of anything that rewrites your tables: on something you have a backup of.
The year of forty CVEs
The committers who own those open items are the same people who fix security bugs, and 2026 has been a bad year to be one of them.
The February 12 minor releases fixed a batch of CVEs, one of which regressed substring() badly enough that an out-of-cycle release followed on February 26. The May 14 releases fixed eleven CVEs, several rated 8.8, and introduced a self-deadlock in WAL replay on 14 through 16 that could wedge a standby following an older primary. The August 13 releases fixed twenty-eight, about half of them heap overflows and type-confusion bugs with arbitrary-code-execution potential, and 18.5 was wrapped and never shipped because a regression was found after the wrap; 18.6 went out instead. In a normal year the project fixes a handful of CVEs. This year it has fixed more than forty by August, and the 18.6 release notes tell you why: the reporter credits include “Ben Morris (in collaboration with Claude and Anthropic Research)” three times, “Amy Burnett (OpenAI Codex Security)” three times, AntAISecurityLab, TrendAI’s Zero Day Initiative, and a long tail of individual researchers, some of whom filed half a dozen findings each.
Beta 1 on June 4 rather than early May was, as far as I can tell, the first symptom: Jonathan Katz announced the date on May 13, the day before the May security release. When he announced beta 4 he said outright that the delay was “primarily due to handling the influx of issues that have been reported that have taken additional time to handle,” and the example he linked was the 18.6 release notes. Nathan Bossart has since proposed moving from four minor releases a year to six or eight, on a trial basis starting in 2027, for the same reason: “the recent influx of bug reports.”
Nobody is going to say this on the list, so I will: a release cycle sized for the committer bandwidth of 2024 was run in the security environment of 2026, by the same few dozen people, and something had to give. What gave was the beta schedule.
The LLM in the room
I promised a short section on this, and it will be short, but it can’t be skipped, because the tools are in every thread I’ve linked above.
The reversion list that reshaped this release was generated by Robert Haas asking Claude which patches had needed the most post-freeze fixes. The locale reverts, the pg_get_*_ddl() redesign item, and the 64-bit MultiXactOffset upgrade problems came out of Noah Misch’s late-August sweep of master with Claude Opus 5; Jungwirth’s fourteen FOR PORTION OF findings are the ones Misch turned up “with some LLM investigation”; and Misch’s analysis of the v19 FSM change that broke torn-page recovery, which Alexander Korotkov then reverted from all six branches, came with a test written by Claude. Thom Brown found the REPACK decoding crash by, in his words, setting Claude on the problem after failing to break it by hand; the LLM found a real cluster-killing bug and got the remedy wrong. Haas found the online checksums hole with Claude. Vignesh C ran Claude over the EXCEPT TABLE publication code, filed five findings with patches, and had an open item 41 minutes later; Amit Kapila’s reply was “Thanks for doing an AI based review of this feature.” Tom Lane’s replacement of the planner’s join-removal machinery on August 28, back-patched to 16, ends its commit message with “Full disclosure: initial drafts of this patch were made with Claude Opus 4.8.”
The current is not all one way. David Rowley sent back a comment with “an awful AI whiff to it”; Tom Lane threw out a set of AI-generated test cases as “not worth the development effort nor the forevermore test runtime cost”; Mihail Nikalayeu flagged his own test suite as AI-generated and unreviewed. Those are the right instincts and they are being applied one patch at a time.
So, Plageman’s question: are we finding more bugs sooner, or are there more bugs? Both, I think, and the second is the less interesting half. The features on Haas’s list were committed with known gaps; the tools didn’t put those gaps there. What the tools changed is the discovery rate, permanently, and in both directions: the security reporters are using them to find memory-safety bugs in twenty-year-old code, and the committers are using them to find design bugs in five-month-old code. A beta period that runs from June to September was calibrated for the old rate. The community has been using the old calendar to process a new volume of findings, and that is the whole story of this summer in one sentence.
I (and PGX) uses these tools too, and this post was drafted with Claude’s assistance (apparently, Clause is the project standard coding AI). I mention it because the disclosure norm Tom Lane just set in a commit message is a good one, and it should apply to blog posts as much as to patches.
Is the process broken?
No. But it is mis-tuned in a specific way, and the September we just had tells you where.
The reverts are the process working. The RMT (Bossart, Heikki Linnakangas, and Plageman this year) has the power to revert over objections and has mostly not needed to use it; Eisentraut, Langote, Korotkov, and Davis pulled their own work. That is the culture doing what it is supposed to do, and it is worth being clear about, because the alternative reading, that PostgreSQL shipped five broken features and the community is scrambling, is wrong. Nothing has shipped.
What is mis-tuned is the freeze. April 8 is a cliff, and cliffs get jumped. Eight major features in five weeks, three of them in the last three days, one with a numbered list of holes in its own commit message, one on freeze day itself: that is a schedule producing the behavior it rewards, not eight independent lapses of judgment. The fix the community has always relied on is the beta period, and the beta period has now demonstrated that it cannot absorb this much unfinished work in this much time, especially when the same people are also shipping forty CVE fixes.
Two proposals are on the table. Drake’s, to move the release to spring, would trade the summer testing window for a winter one and give the six features time to mature; it also means a PostgreSQL 19 eighteen months after 18, which the project has never done voluntarily. Bossart’s, to ship minors every six to eight weeks, addresses the security side of the load and not the feature side. Neither addresses the freeze. Gustafsson’s argument that the September fix work benefits v20 regardless is correct and is also the argument for doing that work in June.
No one is asking me, but my opinion: run the scary patch contest in May, not August. The data Haas fed to Claude on August 25 existed on May 25. A feature that has needed fifteen post-freeze fixes by the end of beta 1 is a feature that should have to argue for staying in, at beta 1, before the release notes and the conference talks and the blog posts (mine included) have made it the headline. The RMT has the authority to do that today. What it lacks is the convention, and conventions in this community are set by someone doing the thing once and it not being a disaster.
PostgreSQL 19 will ship, probably in the last week of October, right after PGConf.EU in Valencia, smaller than beta 1 and better for it. The interesting question for the community is whether the April 8 that produced this September gets a different rule next year.