Incident brief
Active SQL transaction
VACUUM (and a few other commands) refuse to run while a transaction block is still open. PostgreSQL rejected the command instead of running it partway.
What lands in your log
ERROR: VACUUM cannot run inside a transaction block
In 10 seconds
- What triggers it
- BEGIN a transaction.
- Fix
- Run VACUUM on its own, outside any BEGIN/COMMIT block (plain autocommit mode).
- Proof
- Reproduced on PostgreSQL 16.14 → Running VACUUM inside an open transaction was rejected with SQLSTATE 25001. The session was unaffected afterward.
Fix
What to do right now
Application-level steps for this error.
- Run VACUUM on its own, outside any BEGIN/COMMIT block (plain autocommit mode).
- The same restriction applies to other commands too, such as CREATE DATABASE, see the premium test.
- Wrapping VACUUM in a PL/pgSQL DO block does not get around the restriction, see the counterexample.
VACUUM;For this error
See this error live on the server
Run these against the affected instance to confirm the diagnosis before you act.
Active SQL transaction depends on the current connection's transaction state. Confirm that state on the same connection before changing application flow.
Affected backend · open transaction
Read transaction state without inferring it from a pooler's connection state.
SELECT pid, state, xact_start, now() - xact_start AS transaction_age,
left(query, 120) AS query
FROM pg_stat_activity
WHERE pid = pg_backend_pid();Why it happens
What PostgreSQL is telling you
The mechanism behind the error, grounded in the official manual, not paraphrased.
PostgreSQL 16 Documentation, VACUUM
VACUUM cannot be executed inside a transaction block.Read the full section on postgresql.org →
The blocked VACUUM
Per the manual, VACUUM cannot be executed inside a transaction block, it needs to run and finish on its own, outside any surrounding BEGIN/COMMIT.Confirming the session still works
The blocked VACUUM didn't affect the session, the next statement ran normally.Reproduce & verify
A real, single-session PostgreSQL reproduction
A literal transcript of SQL run against a live PostgreSQL instance in an isolated lab. The commands below are exactly what was executed.
- 1BEGIN a transaction.
- 2Run VACUUM inside it.
- 3SQLSTATE 25001 is reported; the transaction is aborted.
One client: open a transaction, then run VACUUM inside it.
-- No table needed: the restriction applies at the transaction-block level, not to a specific table.
SELECT 'no schema required' AS setup_note;BEGIN;
VACUUM;
ROLLBACK;SELECT 1 AS session_still_alive;What PostgreSQL actually returned
setup_note
--------------------
no schema required
(1 row)BEGIN
ERROR: VACUUM cannot run inside a transaction block
ROLLBACK session_still_alive
----------------------
1
(1 row)The manual's transaction-block restriction isn't unique to VACUUM. This was tested directly: CREATE DATABASE, a completely different command, run inside the same kind of open transaction.
Without this
Above: VACUUM inside a transaction block is rejected with SQLSTATE 25001.
With this, tested
Below: CREATE DATABASE inside the same kind of open transaction is rejected with the very same SQLSTATE.
- A second operational test: exact SQL, raw output, measured result, and engineer notes
- Fix that doesn't actually escape the restriction: exact SQL, output, and verdict
- A manual-grounded production interpretation of the lab result
Card required. Cancel before day 7 and you are not charged.
Connected
Everything this error touches
Every page this SQLSTATE connects to: the concept that explains it, the runbooks that fix it, the parameters you tune to prevent it, and the sibling errors it travels with. All real cross-references. Jump straight in, or open the full interactive map.
Verification
- Last verified
- 2026-07-16 (Docker lab, PostgreSQL 16.14)
- Verification scope
- Verified against PostgreSQL 16.14 in an isolated lab environment
- Audit status
- reviewed
Went further?
Pro unlocks the second lab proof
Free page stops the bleeding. Pro adds the operational test, SQLSTATE audit, and deeper evidence, same error, more certainty.