MP026critical

ban-drop-table

DROP TABLE permanently removes the table and all its data.

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

What triggers it

Fires on any DropStmt whose removeType is OBJECT_TABLE — that is, DROP TABLE, with or without CASCADE.

What does not

Any DROP statement that is not a DropStmt, or one that does not target OBJECT_TABLE (DROP INDEX, DROP TYPE, DROP VIEW, and so on), returns null before the message is built.

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

DROP TABLE takes ACCESS EXCLUSIVE for the duration of the drop. On a normal table this is typically fast, metadata-level work — the real danger is not lock duration, it is that the drop is instant and unrecoverable without a backup.

Why it matters

DROP TABLE is irreversible and acquires ACCESS EXCLUSIVE lock. All data, indexes, constraints, and triggers are permanently destroyed. Consider renaming the table first as a soft-delete.

The operation, and the mitigation

Flagged

DROP TABLE users;

Mitigated — still flagged

-- Soft-delete: rename first, drop later after verification
ALTER TABLE users RENAME TO users_deprecated;
-- After confirming no dependencies:
DROP TABLE users_deprecated;

This operation is irreversible, so there is no syntax that makes it safe. The second block is what care looks like — and MigrationPilot still flags it. The mitigation is process: confirm nothing reads the object, keep a way back, and do it in a window where you can watch.

What it assumes

Fires on every DROP TABLE unconditionally, including drops of genuinely obsolete or empty tables in a controlled cleanup migration — it has no way to distinguish those from an accidental drop of a live table.

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.

DROP TABLE is the only operation in this handbook with no recovery path.

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

What the CLI prints

migrationpilot analyze migration.sql
✗ [MP026] CRITICAL (line 1)
  DROP TABLE "users" permanently removes the table and all its data. This is irreversible and takes an ACCESS EXCLUSIVE lock.

  Safe alternative:
  -- Step 1: Rename the table (keeps data as backup)
  ALTER TABLE users RENAME TO users_deprecated;
  
  -- Step 2: After confirming no application depends on it, drop later
  -- DROP TABLE users_deprecated;

  Why: DROP TABLE is irreversible. It permanently deletes the table, all rows, indexes, constraints, triggers, and policies. In production, this means instant data loss. Prefer renaming the table first, keeping it as a backup, then dropping later after confirming no dependencies.
  Docs: https://migrationpilot.dev/rules/mp026

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 MP026
DROP TABLE users;

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

.migrationpilotrc.yml
rules:
  MP026: false

# or keep it, and downgrade it
rules:
  MP026:
    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 MP026 in the playground

Related rules