# How to Modify User Privileges in PostgreSQL Databases PostgreSQL is an open source, object-relational database built for extensibility, data integrity, and speed. Its concurrency support makes it fully ACID-compliant, and it supports dynamic loading and catalog-driven operations to let users customize its data types, functions, and more. By default, PostgreSQL database clusters come with a user, `doadmin`, which has full access to every database you create. Instead of using `doadmin` to access the database, we recommend creating additional users that only have the privileges they need, following the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege). Additionally by default, every database cluster is publicly accessible. To limit access, you can [add trusted sources](https://docs.digitalocean.com/products/databases/postgresql/how-to/secure/index.html.md#firewalls) or manage user permissions by following this guide. You can [create a new user in the control panel](https://docs.digitalocean.com/products/databases/postgresql/how-to/manage-users-and-databases/index.html.md), but you currently can’t set a user’s privileges in the control panel, so you need to use a command-line PostgreSQL client like [`psql`](https://www.postgresql.org/docs/current/app-psql.html). ## Modify PostgreSQL User Permissions First, [connect to your database cluster](https://docs.digitalocean.com/products/databases/postgresql/how-to/connect/index.html.md) as the admin user, `doadmin`, by passing the cluster’s connection string to `psql`. ```shell psql "postgresql://doadmin:your_password@cluster-do-user-1234567-0.db.ondigitalocean.com:25060/defaultdb?sslmode=require" ``` This brings you into the interactive shell for PostgreSQL, which changes your command prompt to `defaultdb=>`. From here, connect to the database that you want to modify the user’s privileges on. ```sql defaultdb=> \connect example_database ``` Connecting to the database changes the command prompt to the database’s name and displays output like this: ``` SSL connection (protocol: TLSv1.2, cipher: ECDHE-RSA-AES256-GCM-SHA384, bits: 256, compression: off) You are now connected to database "example_database" as user "doadmin". ``` From here, the commands you need to execute depend on the permissions you want the user to have. Learn more about [PostgreSQL privileges in their documentation](https://www.postgresql.org/docs/9.1/ddl-priv.html). As an example, to make a **read-only user**, first revoke all of the user’s default privileges, then give `CONNECT` access. From there, add `SELECT` privileges on the existing tables in the database and set `SELECT` privileges as their default for any other tables created in the future. ```sql REVOKE ALL ON DATABASE example_database FROM example_user; GRANT CONNECT ON DATABASE example_database TO example_user; GRANT SELECT ON ALL TABLES IN SCHEMA public TO example_user; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO example_user; ``` You need to run these commands on each database you want this user to have these privileges on. You can also modify these commands to give the user different permissions. For example, changing the permissions from `SELECT` to `INSERT, SELECT` will make a user that can both read and write data. ## Check PostgreSQL User Privileges Once you’re [connected to your database cluster](https://docs.digitalocean.com/products/databases/postgresql/how-to/connect/index.html.md), you can use the `\du` command to list users that currently exist and see their roles. ```sql \du ``` ``` List of roles Role name | Attributes | Member of ---------------+------------------------------------------------------------+----------- \_dodb | Superuser, Replication | {} doadmin | Create role, Create DB, Replication, Bypass RLS | {} postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {} example_user | | {} ``` You can verify that a privilege change completed successfully by querying the database privileges table for the user: ```sql SELECT table_catalog, table_schema, table_name, privilege_type FROM information_schema.table_privileges WHERE grantee = 'example_user'; ``` The output will display the new privileges. For example, if you granted only `SELECT` privileges, the output would look like this: ``` table_catalog | table_schema | table_name | privilege_type ------------------+--------------+------------+---------------- example_database | public | account | SELECT ``` You can also verify that the user’s permissions are changed by logging into the database cluster as the new user, then connecting to the database and testing commands. For example, if you try to `INSERT` into a database as a read-only user, you should receive an error like `ERROR: permission denied for table account`.