Permission denied for relation в PostgreSQL: как настроить права доступа

Вид ошибки:

ERROR:  permission denied for relation table_name

    

Что означает ошибка permission denied for relation?

Эта ошибка появляется, когда пользователь пытается выполнить действие (например, прочитать данные из таблицы или записать их), но у него нет на это прав.

Важно знать: «relation» — в PostgreSQL это не только таблицы, в этот термин входят и представления и другие объекты.

Основные причины

Причина одна — отсутствие нужных привилегий, но сценариев, в которых это происходит, несколько:

  • нет прав USAGE на schema
  • relation был создан другим пользователем и при этом не были выданы права текущему
  • нет прав у вызывающего на таблицы, которые используются во view
  • RLS (Row Level Security) - права на доступ к конкретным строкам
  • search_path указывает в другую схему, где нет нужных прав
  • запрос выполняется не от того пользователя

1. Не определили права при создании relation

При создании объекта в базе данных, права на этот объект присваиваются роли, которая создала объект. Если к объекту обратиться от другой роли, то получим ошибку permission denied. Чтобы этого не произошло после создания надо указать какими правами должны обладать другие роли.

Добавить права на таблицу другим пользователям:

-- Есть три пользователя: root, developer, user
-- От имени root выполняется запрос:
CREATE TABLE table_name (...);
-- Права на таблицу есть только у root

GRANT USAGE ON SCHEMA public TO developer; -- выдать права на использование схемы (если у пользователя нет прав на схему,
                                            -- то получим ошибку даже если есть права на таблицу)
GRANT USAGE ON SCHEMA public TO user;

GRANT DELETE, INSERT, SELECT, UPDATE ON table_name to developer; -- выдать права на чтение, запись, удаление и обновление разработчику

GRANT SELECT ON table_name to user; -- выдать права только на чтение для пользователя (остальные операторы будут давать ошибку)

ALTER TABLE table_name OWNER TO developer; -- сделать владельцем таблицы

    

В PostgreSQL для столбцов id часто используют sequence (специальная сущность PostgreSQL, которая автоматически увеличивает значение столбца, при вставке новой строки). В таком случае если нужно выдать права на INSERT для таблицы с serial нужно выдать права и на саму sequence.

Пример с SEQUENCE:

-- От имени root выполняется запрос:
CREATE TABLE table_name (
    id serial,
    ...
);

GRANT DELETE, INSERT, SELECT, UPDATE ON table_name to developer; -- выдать права для таблицы
GRANT USAGE, SELECT ON SEQUENCE table_name_id_seq TO developer; -- выдать права для секвенции (USAGE нужен для возможности выполнить nextval())

ALTER DEFAULT PRIVILEGES IN SCHEMA public
    GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO developer; -- автоматически выдавать права для всех объектов
                                                                    -- которые будут созданы текущим пользователем (для уже существующих не применится) в схеме public

    

2. Row Level Security

С помощью RLS можно добавить дополнительный слой для безопасности и ограничить с помощью политики доступ для пользователя только конкретными строками

Пример RLS:

ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;

SELECT * FROM table_name; -- может вернуть пустой результат, даже если есть права на таблицу
INSERT INTO table_name () VALUES (); -- ошибка "new row violates row-level security policy" (не permission denied, но тоже ошибка из-за отсутствия прав)

CREATE POLICY client_old_data_policy ON table_name
FOR SELECT
TO client
USING (created_at > '2026-01-01'::date); -- разрешает выборку для пользователя client только строк созданных после 2026-01-01

    

3. Запрос выполняется не от того пользователя

Фактически это та же проблема, но проявляется она уже на стороне приложения. Например, если у приложения есть админка, то можно настроить выполнение запросов от разных пользователей со стороны пользовательской части и со стороны админки. Однако при этом надо внимательно следить чтобы переключение происходило вовремя.

Узнать от какого пользователя будет выполнен запрос:

SELECT current_user;

    

Как проверить текущие права доступа для таблицы:


SELECT grantee, array_agg(privilege_type)
FROM information_schema.role_table_grants
WHERE table_name = 'goods'
GROUP BY grantee;

    

Заключение

Иметь несколько ролей (пользователей) с минимальными нужными им правами это хорошая практика, которая позволяет повысить безопасность продукта. Ошибка permission denied for relation легко решить, если понимать, как работают права в PostgreSQL. Главное — чётко определить, какие действия должен выполнять пользователь, и назначить соответствующие привилегии.

Быстрое решение:

  1. Проверить пользователя SELECT current_user;
  2. Дать права на schema GRANT USAGE ON SCHEMA public TO role;
  3. Дать права на таблицу GRANT SELECT ON table_name TO role;
  4. Дать права на sequence GRANT USAGE ON SEQUENCE ... TO role;
  5. Проверить RLS SELECT * FROM pg_policies WHERE tablename = 'table_name';