MP065critical

ban-lock-table

Explicit LOCK TABLE in migrations blocks queries and can cause deadlocks.

operation
Tables
lock taken
ACCESS EXCLUSIVE
remediation
Manual rewrite
category
Lock safety

What triggers it

Any explicit LockStmt — a LOCK TABLE statement naming one or more relations — regardless of mode. The rule reads lockStmt.mode only to report which of PostgreSQL's lock modes was requested.

What does not

The only guard is !lockStmt?.relations, so the rule fires on every LOCK TABLE the parser produces. There's no negative case beyond a statement that isn't a LockStmt at all.

Where it applies

Applies to every PostgreSQL version MigrationPilot targets. It works on the SQL text alone — no database connection needed.

The lock, and what it blocks

Whatever mode the statement names, from ACCESS SHARE up through ACCESS EXCLUSIVE — the rule reports the specific mode from lockStmt.mode, defaulting the message to ACCESS EXCLUSIVE only when that field is missing. At the high end, ACCESS EXCLUSIVE blocks every other lock mode, including plain reads.

Why it matters

LOCK TABLE acquires an explicit lock that can block reads and writes. PostgreSQL DDL statements automatically acquire the correct lock — explicit LOCK TABLE is rarely needed and often indicates a flawed migration strategy. High lock modes (EXCLUSIVE, ACCESS EXCLUSIVE) block all other operations.

Unsafe, and safe

Flagged

LOCK TABLE users IN ACCESS EXCLUSIVE MODE;

Safe alternative

-- Let PostgreSQL acquire locks automatically via DDL
-- No explicit LOCK TABLE needed
ALTER TABLE users ADD COLUMN email TEXT;

What it assumes

The rule treats every explicit LOCK TABLE as suspect, but there are legitimate uses — deliberately serializing access to a small table, for instance — where an explicit lock is the right tool and PostgreSQL's automatic DDL locking doesn't apply.

What backs this rule

Every rule is a claim about PostgreSQL, so it carries what the claim rests on: a handbook chapter that cites the manual, the incidents that put it there, and the version it was last checked against.

Entry 02 covers the mechanism: a blocked DDL statement blocks everything behind it.

verified against
PostgreSQL 17.10
last checked
2026-08-11
confidence
High

PostgreSQL manual

What the CLI prints

migrationpilot analyze migration.sql
✗ [MP065] CRITICAL (line 1)
  Explicit LOCK TABLE on users in ACCESS EXCLUSIVE mode. PostgreSQL DDL acquires locks automatically. Remove the explicit lock or restructure the migration.

  Why: LOCK TABLE acquires an explicit lock that can block reads and writes. PostgreSQL DDL statements automatically acquire the correct lock. Explicit LOCK TABLE is rarely needed and often indicates a flawed migration strategy. High lock modes (EXCLUSIVE, ACCESS EXCLUSIVE) block all other operations.
  Docs: https://migrationpilot.dev/rules/mp065

Generated by running the CLI's own formatter over the flagged example above, so it is the text the tool actually produces. A real run also reports the other rules that fire on the same statement; those blocks are left out here.

Turning it off

For one statement, put a comment on the line before it:

-- migrationpilot-disable MP065
LOCK TABLE users IN ACCESS EXCLUSIVE MODE;

For the whole project, in .migrationpilotrc.yml — by name or by id:

.migrationpilotrc.yml
rules:
  MP065: false

# or keep it, and downgrade it
rules:
  MP065:
    severity: warning

Try it

Open this rule's flagged example in the playground. It runs in your browser — edit it and watch the finding appear and disappear.

Run MP065 in the playground