The crucial thing to understand here is that privileges are not heirachical and are not inherited from containing objects. ALL
means all privileges for this object not all privileges for this object and all contained objects.
When you grant ALL
on a database, you're granting CREATE, CONNECT, TEMP
. These are actions on the database object its self:
CONNECT
: Connect to the DBCREATE
: Create a schema (not a table)TEMP
: Create temporary objects, including but not limited to temp tables
Now, each PostgreSQL database by default has a public
schema that's created when the database is created. This schema has all rights granted to the role public
, of which everybody is implicitly a member. For a schema, ALL
means CREATE, USAGE
:
CREATE
: Create objects (including tables) within this schemaUSAGE
: List objects in the schema and access them if their permissions permit
If you do not specify the schema to create an object like a table in, the database engine uses the search_path
, and by default the public
schema is first on the search_path
so the table is created there. Everyone has rights to public
by default, so the creation is allowed. The users' rights on the database are irrelevant at this point, as the user isn't trying to do anything to the database object its self, only a schema within it.
It doesn't matter that you haven't granted the user any rights other than granting CONNECT
on the database, because the public
schema permits all users to create tables in it by default. Daniel has already explained how to revoke that right if desired.
If you want to delegate every right explicitly, revoke all from public, or simply drop the public schema. You can create a new template database with this change applied if you want to. Alternately you can apply it to template1
, but that'll likely break lots of 3rd party code that assumes that public
exists and is writeable.
This might make more sense if you look at a filesystem analogy.
If I have the directory structure (mode simplified to only show the mode that applies to the current user):
/dir1 mode=r-x/dir1/dir2 mode=rwx
then I cannot create anything within /dir1
, because I do not have write permission. So if I touch /dir1/somefile
I will get a permission denied error.
However, I do have permission to look inside /dir1
and to access contained files and directories, including /dir1/dir2
. I have write permission on dir2
. So touch /dir1/dir2/somefile
will succeed, even though I don't have write permission to dir1
.
Same thing with databases and schemas.