MP085warning

warn-grant-widening

GRANT to PUBLIC, GRANT ALL, or a blanket schema-wide grant hands out more privilege than the migration needs.

operation
Privileges and RLS
lock taken
no table lock
remediation
Manual rewrite
category
Privileges & RLS

What triggers it

A GrantStmt where is_grant is true and at least one of: the grantees include the PUBLIC pseudo-role (ROLESPEC_PUBLIC), the privileges list is empty (the parser's representation of ALL PRIVILEGES), or the target type is ACL_TARGET_ALL_IN_SCHEMA.

What does not

Non-GrantStmt statements, REVOKE (is_grant !== true — narrowing access is never flagged), and any GRANT that names specific privileges to a specific non-PUBLIC role or object, where none of the three widening conditions hold.

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

None — this is about privilege scope, not locking.

Why it matters

Privileges granted in a migration are permanent and almost never revisited. TO PUBLIC is the one that resists auditing: it does not grant to the roles that exist, it grants to the role every user implicitly has, including users created long after the migration ran. GRANT ALL also confers TRUNCATE, which empties the table in one statement, and a schema-wide grant covers only the tables that happened to exist when it ran.

Unsafe, and safe

Flagged

GRANT ALL ON users TO app;
-- app can now TRUNCATE users

GRANT SELECT ON users TO PUBLIC;
-- every role in the cluster, including ones created next year

Safe alternative

-- Name the privileges, name the role.
GRANT SELECT, INSERT, UPDATE ON users TO app_role;

-- If PUBLIC access was inherited from an older migration, take it back.
REVOKE ALL ON users FROM PUBLIC;

What it assumes

Assumes broad grants are always accidental, but PUBLIC access, ALL PRIVILEGES, or a schema-wide grant are sometimes exactly what's intended — an admin role or a deliberately world-readable reporting schema looks identical to an oversight to this rule, so both get flagged the same way.

What the CLI prints

migrationpilot analyze migration.sql
⚠ [MP085] WARNING (line 1)
  GRANT ALL PRIVILEGES on users: grants ALL PRIVILEGES rather than the specific ones needed. Grant only the privileges the application actually uses, to a named role.

  Safe alternative:
  -- Grant the specific privileges to a named role instead:
  GRANT SELECT, INSERT, UPDATE ON users TO app_role;
  
  -- If PUBLIC access was inherited from an older migration, revoke it explicitly:
  REVOKE ALL ON users FROM PUBLIC;

  Why: Privileges granted in a migration are permanent and rarely revisited. GRANT ... TO PUBLIC reaches every role in the cluster, including roles created years later, so it is the one grant that cannot be audited by listing current users. GRANT ALL hands over TRUNCATE and REFERENCES alongside the read access that was actually wanted. Blanket ON ALL TABLES IN SCHEMA grants apply to whatever happens to exist at that moment, which makes the resulting privilege set a function of migration ordering rather than intent.
  Docs: https://migrationpilot.dev/rules/mp085

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 MP085
GRANT ALL ON users TO app;

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

.migrationpilotrc.yml
rules:
  MP085: false

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

Related rules