Hi I'm trying to create a login role (user) with a fairly minimal ability to modify the database. They should be able to select, delete, create triggers, insert and update. I would then like to have multiple accounts which are members of user so they have the same permissions but I can log edits for individual users.

I'm using pgadmin for my database design and my program accesses this with QtSQL.

The error message I get is caught by Qt when trying to select some data as a test. When I run the same code as the database owner and superuser I have no problems.

bool run_query(const QString & q){
    QSqlDatabase db = QSqlDatabase::database("default");
    QSqlQuery query(db);


    if (!query.isActive()){
        QMessageBox::warning(0, QObject::tr("Database Error"),
        return false;

    while (query.next()){
        QString title = query.value(0).toString();
        std::cerr << qPrintable(title) << std::endl;
    return true;

run_query("Select forename from contacts;");

ERROR: permission denied for relation contacts QPSQL: Unable to create query

So far I've created the role (user).

-- Role: user

-- DROP ROLE "user";

  ENCRYPTED PASSWORD 'md54d45974e13472b5a0be3533de4666414'
COMMENT ON ROLE "user" IS 'Low level user';

As this gave the previous problems. I tried adding permissions for public for the database but this didn't work either.

Now I've no idea where to look for a solution. Any help is much appreciated. Thanks.


2 Answers 2


GRANTing ALL permissions for public to the database is mostly redundant (as public has connect, temporary by default, so you'd only be adding CREATE which you probably don't want to do). You probably expected a GRANT ALL on the database to result in a recursive GRANT ALL to contained schemas and tables. GRANT is not recursive, so this doesn't happen; a GRANT ALL on a database just grants CONNECT and TEMPORARY rights to the database, with no effect on contained schemas and tables.

The default GRANTs are, from the docs on GRANT:

PostgreSQL grants default privileges on some types of objects to PUBLIC. No privileges are granted to PUBLIC by default on tables, columns, schemas or tablespaces. For other types, the default privileges granted to PUBLIC are as follows: CONNECT and CREATE TEMP TABLE for databases; EXECUTE privilege for functions; and USAGE privilege for languages. The object owner can, of course, REVOKE both default and expressly granted privileges. (For maximum security, issue the REVOKE in the same transaction that creates the object; then there is no window in which another user can use the object.) Also, these initial default privilege settings can be changed using the ALTER DEFAULT PRIVILEGES command.

So you can see you don't need to GRANT anything on the database unless you want the user to be able to create schemas, etc. You need to:

  • GRANT USAGE ON SCHEMA myschema TO theuser; for any schema other than public. CREATE can be granted if you want the user to be able to make tables, views, etc.
  • GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE sometable TO theuser; for tables. I've omitted the TRUNATE, REFERENCES and TRIGGER rights as you probably don't want to grant them.
  • GRANT USAGE ON SEQUENCE sometable_somecolumn_seq TO theuser; for any sequences that are used in table defaults, either explicitly or via a SERIAL or BIGSERIAL column.

... etc. See the manual for GRANT linked above for full definitions of what the privileges do, which are available on which objects, etc. Take note of the wildcard ALL TABLES and ALL SEQUENCES options.

If this seems like too much hassle to do for each table, view, schema, sequence, etc, you can in Pg 9.1 and above use ALTER DEFAULT PRIVILEGES to change the default GRANTs on new objects.


It looks like you need something like this:


By the way, I hope "user" is not an actual user name you chose. Not only does it fail to convey much about the semantics of the role, but you will need to quote it everywhere, which can be something of a bother and lead to confusion when there is a problem. If you pick a name for the role which is not a keyword and indicates what the role is for, you will probably be happier with the results.

I'm not sure that bringing the QtSQL layer into the question helps anyone understand the issue. If you can show the issue in a session in psql you might attract more answers.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.