Table Permissions

Created at: 2025-05-09

Basics

Ownership

Granting Specific Privileges

Table Privileges

The full list of privileges can be seen here: https://www.postgresql.org/docs/current/ddl-priv.html

But the interesting bits are:

  REVOKE ALL ON public.foo FROM sweet_user;
  ALTER TABLE public.foo ADD COLUMN bar INTEGER DEFAULT 42;

  GRANT SELECT (bar) ON public.foo TO sweet_user;

  -- The user doesn't show up here because it does not have TABLE privileges.
  SELECT
    grantee,
    table_schema AS schema,
    table_name,
    privilege_type AS privilege,
    grantor
  FROM
    information_schema.table_privileges
  WHERE
    table_name = 'foo'
    AND table_schema = 'public';

  -- But it does show up here as they now have COLUMN privileges.
  SELECT
    grantee,
    table_schema,
    table_name,
    column_name,
    privilege_type
  FROM
    information_schema.column_privileges
  WHERE privilege_type = 'SELECT'
    AND table_name = 'foo'
    AND table_schema = 'public';
  --      grantee      | table_schema | table_name | column_name | privilege_type
  ---------------------+--------------+------------+-------------+----------------
  -- marcelo.fernandes | public       | foo        | bar         | SELECT
  -- marcelo.fernandes | public       | foo        | id          | SELECT
  -- sweet_user        | public       | foo        | bar         | SELECT

Can the user be blocked from querying a table even when they have CREATE

permission in the schema?

CREATE USER user1;
CREATE USER user2;

DROP TABLE IF EXISTS public.foo;
CREATE TABLE public.foo (id SERIAL PRIMARY KEY);
INSERT INTO public.foo SELECT generate_series(1, 1000);

SET ROLE user1;
SELECT * FROM public.foo;
-- ERROR:  permission denied for table foo

SET ROLE user2;
SELECT * FROM public.foo;
-- ERROR:  permission denied for table foo

SET ROLE "marcelo.fernandes";

-- User 1 has permission to the table
GRANT SELECT ON public.foo TO user1;
-- User 2 has permission to the schema
GRANT CREATE ON SCHEMA public TO user2;

SET ROLE user1;
SELECT count(*) FROM public.foo; -- 1,000
SET ROLE "marcelo.fernandes";

-- Still permission denied!
SET ROLE user2;
SELECT count(*) FROM public.foo;
-- ERROR:  permission denied for table foo
SET ROLE "marcelo.fernandes";

Tips

For testing permissions, you can always:

SET ROLE sweet_user;
-- test stuff here
SET ROLE "marcelo.fernandes";