Erreur PostgreSQL : permission denied for table / schema
ERROR: permission denied for table orders
-- variante a livello di schema:
ERROR: permission denied for schema app
Le rôle sous lequel vous êtes connecté n'a pas le privilège dont l'instruction a besoin : SELECT/INSERT/UPDATE/DELETE sur une table, USAGE ou CREATE sur un schéma, USAGE sur une séquence. (Les versions plus anciennes de PostgreSQL formulent la première comme « permission denied for relation ».) La solution est toujours un GRANT — la partie intéressante est pourquoi le grant manquait.
Ce que signifie cette erreur
Les privilèges de PostgreSQL sont par objet et ne se propagent pas en cascade : pour lire app.orders vous avez besoin à la fois de USAGE sur le schéma app et de SELECT sur la table. Les propriétaires détiennent implicitement tous les privilèges sur leurs objets — ce qui est exactement pourquoi tout fonctionne en développement (où l'application se connecte en tant que propriétaire) et casse en production (où ce n'est pas le cas).
Deux variantes voisines à reconnaître : permission denied for sequence orders_id_seq signifie que le rôle peut écrire la table mais pas tirer d'ID de sa séquence ; permission denied for schema public a commencé à apparaître largement avec PostgreSQL 15, qui a cessé de laisser chaque utilisateur créer des objets dans public par défaut.
Causes fréquentes
- Objets créés par un rôle différent. Les migrations s'exécutent en tant que
migratorou un admin ; l'application se connecte en tant queapp_user; personne n'a accordé àapp_userquoi que ce soit sur les nouvelles tables. - Les grants ne sont pas rétroactifs vers l'avant :
GRANT ... ON ALL TABLES IN SCHEMAcouvre uniquement les tables existantes. Les tables créées la semaine prochaine ne sont pas couvertes — c'est à cela que sertALTER DEFAULT PRIVILEGES. - Le piège d'
ALTER DEFAULT PRIVILEGES: il ne s'applique qu'aux objets créés par le rôle pour lequel il a été défini. Le définir pour vous-même alors que les migrations s'exécutent sous un autre rôle ne fait rien. - Absence de
USAGEsur le schéma — les grants sur les tables sont inutiles si le rôle ne peut pas traverser le schéma. - PostgreSQL 15+ :
CREATEsur le schémapublicn'est plus accordé à tout le monde ; des outils qui « fonctionnaient » avant une mise à jour commencent à échouer.
Comment la diagnostiquer
SELECT current_user; -- qui vous êtes vraiment (attention aux poolers)
\dp orders -- privilèges et propriétaire de la table
\dn+ -- privilèges sur les schémas
SELECT has_table_privilege('app_user', 'app.orders', 'SELECT');
Lisez la sortie de \dp sans pitié : une colonne « Access privileges » vide signifie que seul le propriétaire a accès. Et vérifiez qui est le propriétaire — cela explique généralement comment la situation est survenue.
Comment la corriger
-- Le jeu minimal typique pour un rôle applicatif :
GRANT USAGE ON SCHEMA app TO app_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app TO app_user;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA app TO app_user;
-- Et pour les tables FUTURES créées par le rôle des migrations :
ALTER DEFAULT PRIVILEGES FOR ROLE migrator IN SCHEMA app
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;
ALTER DEFAULT PRIVILEGES FOR ROLE migrator IN SCHEMA app
GRANT USAGE, SELECT ON SEQUENCES TO app_user;
-- PostgreSQL 15+, s'il faut créer des objets dans public :
GRANT CREATE ON SCHEMA public TO app_user;
- Notez le
FOR ROLE migrator: les privilèges par défaut doivent être attachés au rôle qui crée les objets. - Alternative structurelle adoptée par beaucoup d'équipes : faire en sorte que tous les objets appartiennent à un rôle dédié
app_owner, exécuter les migrations sous ce rôle, et n'accorder au rôle d'exécution que ce dont il a besoin.
