166

Is there a one-liner that grants the SELECT permissions to a new user postgresql?

Something that would implement the following pseudo-code:

GRANT SELECT ON TABLE * TO my_new_user;
Adam Matan
  • 13,574

10 Answers10

267

I thought it might be helpful to mention that, as of 9.0, postgres does have the syntax to grant privileges on all tables (as well as other objects) in a schema:

GRANT SELECT ON ALL TABLES IN SCHEMA public TO user;
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO user;

To grant permissions also for tables created in the future use:

ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO user;

Here's the link.

TimH
  • 2,786
  • I'll upgrade soon, so this is really good news. Thanks! – Adam Matan Jun 26 '11 at 15:31
  • Does this affect all databases on the server that use the public schema? – kristianp May 28 '14 at 07:20
  • 13
    If I create a new table, will this user have access to the newly created table? – GuiSim Sep 05 '14 at 19:13
  • 14
    @GuiSim No, You have to set the default privileges on a schema, where ytou create the table: http://www.postgresql.org/docs/current/static/sql-alterdefaultprivileges.html – SkyRaT Jan 24 '16 at 09:33
  • 1
    @kristianp No, every database in the PG cluster has its own public schema. It affect all tables (functions) in the schema public for current DB you are connected to. – SkyRaT Jan 24 '16 at 09:36
  • Note: this doesn't work on Redshift yet – Faiz Oct 06 '16 at 06:56
  • I'm trying this, but I'm getting "WARNING: no privileges were granted for xxx" for every table. This is not a particularly helpful message as it tells me nothing about what the problem is. – szeitlin Jul 03 '18 at 18:13
  • @szeitlin Here are two links that should help you figure that out (found by Googling "postgresql WARNING: no privileges were granted for "):
    • https://www.postgresql.org/message-id/24612.1210687964%40sss.pgh.pa.us
    • https://stackoverflow.com/questions/25691037/postgresql-permissions-explained

    Hope that helps.

    – TimH Jul 05 '18 at 11:05
  • I ended up doing this (see below): https://serverfault.com/a/919358/282107 – szeitlin Jul 05 '18 at 18:05
  • @TimH you also have to grant schema access – deFreitas Aug 11 '18 at 16:16
14

My (non-one-liner) solution:

#!/bin/bash

for table in echo "SELECT schemaname || '.' || relname FROM pg_stat_user_tables;" | psql -A -t my_database_name; do echo "GRANT SELECT ON TABLE $table to my_new_user;" echo "GRANT SELECT ON TABLE $table to my_new_user;" | psql my_database_name done

Run from the privileged user, it worked like a charm.

leeand00
  • 4,919
Adam Matan
  • 13,574
12

This can be done with a two-step process.

  1. Run this query:

    select 'grant all on '||schemaname||'.'||tablename||' to $foo;'
    from pg_tables where schemaname in ('$bar', '$baz')
    order by schemaname, tablename;
    

    Replacements:

    $foo = username you want to grant permissions for
    $bar, $baz = schemas you want to grant permissions in (can be just "public")

  2. That's going to give you a list of queries that will generate the required permissions. Copy the output, paste it into another query, and execute.

Moshe Katz
  • 3,182
11

I ended up doing this, and it worked:

ALTER DEFAULT PRIVILEGES IN SCHEMA public 
GRANT SELECT ON TABLES TO PUBLIC;
szeitlin
  • 211
  • 2
  • 3
  • 1
    very good when tables are created afterwards, and read access is meant to be granted by default – arhak May 16 '20 at 13:10
6

I ended up here because my DB user saw only a few tables and not the newer ones. If this is your case, this has helped me.

  1. Grant privileges to all existing tables:

    GRANT SELECT ON ALL TABLES IN SCHEMA public TO user;
    
  2. Grant privileges to all new tables to be created in future (via default privileges):

    ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO user;
    
  3. You can also double-check that all tables are granted correctly.

    • Count all existing tables:

      SELECT COUNT(*)
      FROM pg_catalog.pg_tables
      WHERE schemaname != 'pg_catalog' AND
            schemaname != 'information_schema';
      
    • Count all tables the user has access to:

      SELECT COUNT(*)
      FROM information_schema.role_table_grants
      WHERE grantee = 'user';
      

    The count of last two queries must be the same.

CraZ
  • 218
2

This is what I used:

psql dbname -tc "select 'grant select on '||relname||' to readonly;' from pg_stat_user_tables" | psql dbname

I feel it's more natural to do formatting and where-clauses in sql..

HBruijn
  • 80,330
  • 24
  • 138
  • 209
stox
  • 41
1

I'm working with postgres 8.4 and to give all privileges to a user do the following:

#!/bin/bash

for table in `echo "SELECT schemaname||'.'||relname FROM pg_stat_all_tables WHERE schemaname NOT IN('pg_catalog','pg_toast','information_schema')" | psql -t db `;
do
    echo "grant select on table $table to my_new_user;"
    echo "grant select on table $table to my_new_user;" | psql db
done
Rup
  • 275
  • 5
  • 15
wilson
  • 11
0
DO $$
DECLARE
    schemaname text;
BEGIN
    FOR schemaname IN (SELECT nspname FROM pg_namespace) LOOP
        EXECUTE 'GRANT USAGE, SELECT ON ALL TABLES IN SCHEMA ' || schemaname || ' TO user';
    END LOOP;
END $$;
  • Replace "user" with the appropriate username.

    Note that this query will grant the user "USAGE" and "SELECT" privileges on all tables in all schemas within the database.

    – mustafa bozkurt Jan 16 '23 at 01:40
0

one way to fix this is to write a stored procedure. unfortunately there is no "grant everything to all tables" command or so. you really need a procedure or some external shell script maybe to make this work.

0

The (one-liner solution) script by Adam Matan is great when there are many schema's, but it doesn't work where schema names or table names contain uppercase letters or special characters.

Modified version:

#!/bin/bash

for table in `echo "SELECT '\"' || schemaname || '\".\"' || relname || '\"'  FROM pg_stat_user_tables;" | psql -A -t my_database_name`;
do
    echo "GRANT SELECT ON TABLE $table to my_new_user;"
    echo "GRANT SELECT ON TABLE $table to my_new_user;" | psql my_database_name
done
anneb
  • 206