How to fix VACUUM cannot run inside a transaction block in PostgreSQL

PostgreSQLBEGINNERMEDIUMUpdated Dec 28, 2025· 238 views

VACUUM is a PostgreSQL maintenance command that cannot run inside a transaction block. This error occurs when your connection has an active transaction. Enable autocommit mode or commit before running VACUUM.

Quick fix

Fixes VACUUM cannot run inside a transaction block

import psycopg2

conn = psycopg2.connect("dbname=mydb user=postgres")
conn.autocommit = True
cur = conn.cursor()
cur.execute("VACUUM FULL ANALYZE")
conn.close()
  1. Enable autocommit for your database connection
  2. Use psycopg2.extensions for finer control (Python)
  3. Commit active transactions before VACUUM
  4. Use raw connection for VACUUM in SQLAlchemy
postgresql — error
import psycopg2
conn = psycopg2.connect("dbname=mydb user=postgres")
conn.autocommit = True
cur = conn.cursor()
cur.execute("VACUUM FULL ANALYZE")
conn.close()
VACUUM cannot run inside a transaction block

What this error means

PostgreSQL requires VACUUM to run in autocommit mode because it performs maintenance operations that cannot be rolled back. The VACUUM command removes dead rows and optimizes table storage. When your database connection has an active transaction (the default in most ORMs and drivers), PostgreSQL blocks VACUUM to prevent inconsistent states. This is by design and not a bug—VACUUM is a non-transactional operation.

Typical symptoms

  • VACUUM fails with "ERROR: VACUUM cannot run inside a transaction block"
  • VACUUM ANALYZE or VACUUM FULL commands fail the same way
  • Running VACUUM in your application or script produces the error
  • psycopg2, SQLAlchemy, or other database drivers fail when executing VACUUM
  • Scheduled maintenance jobs cannot execute VACUUM operations

Common causes

  1. Your database connection has an active transaction (autocommit is disabled)
  2. Using an ORM or connection pool that defaults to autocommit=false
  3. Running VACUUM as part of a multi-statement query block
  4. Connection isolation level is not set to autocommit
  5. VACUUM is mixed with other SQL commands in the same transaction

How to fix "VACUUM cannot run inside a transaction block"

1Enable autocommit for your database connection

The most straightforward fix is to enable autocommit mode before executing VACUUM.

For psycopg2 (Python):

python
import psycopg2

conn = psycopg2.connect("dbname=mydb user=postgres")
conn.autocommit = True
cur = conn.cursor()
cur.execute("VACUUM FULL ANALYZE")
conn.close()

For psycopg3 (newer Python driver):

python
import psycopg

conn = psycopg.connect("dbname=mydb user=postgres", autocommit=True)
conn.execute("VACUUM FULL ANALYZE")
conn.close()
2Use psycopg2.extensions for finer control (Python)

If you need more control over isolation levels:

python
import psycopg2
import psycopg2.extensions

conn = psycopg2.connect("dbname=mydb user=postgres")
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
cur = conn.cursor()
cur.execute("VACUUM FULL ANALYZE")
conn.close()

This explicitly sets the connection to autocommit mode.

3Commit active transactions before VACUUM

If you cannot enable autocommit, commit any pending transactions first:

sql
COMMIT;
VACUUM FULL ANALYZE;

Or in application code:

python
# Using SQLAlchemy
from sqlalchemy import text

with engine.connect() as conn:
    conn.commit()  # Commit any pending transaction
    conn.execute(text("VACUUM FULL ANALYZE"))
    conn.commit()

Note: SQLAlchemy may still wrap this in a transaction. See the next step for a better approach.

4Use raw connection for VACUUM in SQLAlchemy

With SQLAlchemy, bypass the ORM transaction handling:

python
from sqlalchemy import create_engine, text

engine = create_engine("postgresql://user:password@localhost/dbname")

# Get a raw DBAPI connection with autocommit
raw_conn = engine.raw_connection()
raw_conn.autocommit = True
cur = raw_conn.cursor()
cur.execute("VACUUM FULL ANALYZE")
raw_conn.close()

This bypasses SQLAlchemy's transaction handling entirely.

5Schedule VACUUM separately in production

In production, avoid running VACUUM from your application. Instead:

1. Use autovacuum (enabled by default):

sql
ALTER TABLE my_table SET (autovacuum_vacuum_scale_factor = 0.05);

2. Schedule with cron or a separate job:

bash
0 2 * * * /usr/bin/psql -U postgres -d mydb -c "VACUUM FULL ANALYZE;" 2>&1 | logger

3. Use a maintenance window with a dedicated connection pool that has autocommit enabled.

Advanced notes

VACUUM is intentionally non-transactional because it requires exclusive locks and must persist changes to the physical database files immediately. PostgreSQL's autovacuum daemon handles routine maintenance automatically, so VACUUM FULL is rarely needed in production. If autovacuum is running too frequently, tune its parameters (autovacuum_naptime, autovacuum_vacuum_scale_factor, autovacuum_vacuum_cost_delay) rather than running manual VACUUM. For tables with GIN indexes, VACUUM also completes pending index insertions. When using connection pooling (PgBouncer, pgpool), ensure your VACUUM connections use session mode, not transaction mode.

Frequently asked questions

What does "VACUUM cannot run inside a transaction block" mean?
PostgreSQL requires VACUUM to run in autocommit mode because it performs maintenance operations that cannot be rolled back. The VACUUM command removes dead rows and optimizes table storage. When your database connection has an active transaction (the default in most ORMs and drivers), PostgreSQL blocks VACUUM to prevent inconsistent states.
How do I fix "VACUUM cannot run inside a transaction block"?
VACUUM is a PostgreSQL maintenance command that cannot run inside a transaction block. This error occurs when your connection has an active transaction. Enable autocommit mode or commit before running VACUUM.
What causes "VACUUM cannot run inside a transaction block"?
Your database connection has an active transaction (autocommit is disabled) Using an ORM or connection pool that defaults to autocommit=false Running VACUUM as part of a multi-statement query block
Is the "VACUUM cannot run inside a transaction block" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading