BLOG POSTS
    MangoHost Blog / How to Use Roles and Manage Grant Permissions in PostgreSQL on a VPS
How to Use Roles and Manage Grant Permissions in PostgreSQL on a VPS

How to Use Roles and Manage Grant Permissions in PostgreSQL on a VPS

Database security becomes critical when your PostgreSQL instance houses sensitive data or serves multiple applications on your VPS. PostgreSQL’s role-based permission system provides granular control over who can access what data, execute which functions, and perform specific operations. This guide walks you through creating roles, managing permissions, and implementing security best practices that protect your database while maintaining operational flexibility for your development and production environments.

Understanding PostgreSQL Roles and Permission Hierarchy

PostgreSQL uses a unified concept called “roles” instead of the traditional users and groups separation found in other database systems. Every entity that connects to PostgreSQL is a role, whether it represents a person, application, or service account.

Roles can have three main types of privileges:

  • Login privileges: Allows the role to connect to the database
  • Membership privileges: Grants inheritance of permissions from other roles
  • Object privileges: Controls access to specific database objects like tables, schemas, and functions

The permission system follows a hierarchical structure where roles can inherit attributes from parent roles, similar to group membership in Unix systems. However, unlike traditional user/group models, any role can be granted to any other role, creating flexible permission chains.

-- View current roles and their attributes
SELECT rolname, rolsuper, rolcreaterole, rolcreatedb, rolcanlogin, rolreplication
FROM pg_roles
ORDER BY rolname;

Step-by-Step Role Creation and Management

Creating Basic Roles

Start by connecting to your PostgreSQL instance on your VPS as the superuser (usually postgres):

sudo -u postgres psql

Create different types of roles for common use cases:

-- Create a login role for application connections
CREATE ROLE app_user WITH LOGIN PASSWORD 'secure_password_here';

-- Create a group role for managing permissions
CREATE ROLE developers;

-- Create a role with specific privileges
CREATE ROLE backup_user WITH LOGIN PASSWORD 'backup_pass' 
    NOSUPERUSER NOCREATEDB NOCREATEROLE;

-- Create a role that can create databases
CREATE ROLE db_admin WITH LOGIN PASSWORD 'admin_pass' 
    CREATEDB CREATEROLE;

Managing Role Membership

Grant roles to other roles to establish permission inheritance:

-- Add app_user to the developers group
GRANT developers TO app_user;

-- Grant multiple roles at once
GRANT developers, backup_user TO db_admin;

-- View role memberships
SELECT 
    r.rolname as role_name,
    m.rolname as member_of
FROM pg_roles r
JOIN pg_auth_members am ON r.oid = am.member
JOIN pg_roles m ON am.roleid = m.oid
ORDER BY r.rolname;

Modifying Existing Roles

-- Change password
ALTER ROLE app_user PASSWORD 'new_secure_password';

-- Add login capability to existing role
ALTER ROLE developers WITH LOGIN;

-- Set connection limit
ALTER ROLE app_user CONNECTION LIMIT 10;

-- Set role as superuser (use carefully)
ALTER ROLE db_admin SUPERUSER;

Implementing Database and Schema-Level Permissions

Database Access Control

-- Create a new database
CREATE DATABASE production_app OWNER app_user;

-- Grant connection privileges
GRANT CONNECT ON DATABASE production_app TO developers;

-- Revoke public access (recommended security practice)
REVOKE ALL ON DATABASE production_app FROM PUBLIC;

-- Grant all privileges to admin role
GRANT ALL PRIVILEGES ON DATABASE production_app TO db_admin;

Schema-Level Security

-- Connect to the target database
\c production_app

-- Create schemas for different application modules
CREATE SCHEMA user_management AUTHORIZATION app_user;
CREATE SCHEMA reporting AUTHORIZATION db_admin;
CREATE SCHEMA audit_logs AUTHORIZATION backup_user;

-- Grant usage on schemas
GRANT USAGE ON SCHEMA user_management TO developers;
GRANT CREATE ON SCHEMA user_management TO developers;

-- Set default privileges for future objects
ALTER DEFAULT PRIVILEGES IN SCHEMA user_management 
    GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO developers;

ALTER DEFAULT PRIVILEGES IN SCHEMA user_management 
    GRANT USAGE, SELECT ON SEQUENCES TO developers;

Table and Object-Level Permission Management

Granular Table Permissions

-- Create sample tables
CREATE TABLE user_management.users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    email VARCHAR(100),
    created_at TIMESTAMP DEFAULT NOW()
);

CREATE TABLE user_management.user_sessions (
    session_id VARCHAR(128) PRIMARY KEY,
    user_id INTEGER REFERENCES user_management.users(id),
    created_at TIMESTAMP DEFAULT NOW(),
    expires_at TIMESTAMP
);

-- Grant specific permissions on tables
GRANT SELECT, INSERT, UPDATE ON user_management.users TO app_user;
GRANT SELECT, DELETE ON user_management.user_sessions TO app_user;

-- Grant read-only access to reporting role
CREATE ROLE reports_readonly;
GRANT USAGE ON SCHEMA user_management TO reports_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA user_management TO reports_readonly;

Column-Level Security

-- Add sensitive column
ALTER TABLE user_management.users ADD COLUMN password_hash VARCHAR(255);

-- Grant column-specific permissions
GRANT SELECT (id, username, email, created_at) ON user_management.users TO reports_readonly;
GRANT UPDATE (email) ON user_management.users TO app_user;

Real-World Use Cases and Implementation Examples

Multi-Tenant Application Setup

-- Create tenant-specific roles and schemas
CREATE ROLE tenant_alpha_app WITH LOGIN PASSWORD 'alpha_secure_pass';
CREATE ROLE tenant_beta_app WITH LOGIN PASSWORD 'beta_secure_pass';

CREATE SCHEMA tenant_alpha AUTHORIZATION tenant_alpha_app;
CREATE SCHEMA tenant_beta AUTHORIZATION tenant_beta_app;

-- Ensure tenants cannot access each other's data
REVOKE ALL ON SCHEMA tenant_alpha FROM PUBLIC;
REVOKE ALL ON SCHEMA tenant_beta FROM PUBLIC;

-- Create shared reporting role with cross-tenant access
CREATE ROLE global_reports WITH LOGIN PASSWORD 'reports_pass';
GRANT USAGE ON SCHEMA tenant_alpha, tenant_beta TO global_reports;
GRANT SELECT ON ALL TABLES IN SCHEMA tenant_alpha TO global_reports;
GRANT SELECT ON ALL TABLES IN SCHEMA tenant_beta TO global_reports;

Development Environment Role Structure

-- Development team roles
CREATE ROLE dev_team;
CREATE ROLE senior_devs;
CREATE ROLE junior_devs;

-- Individual developer accounts
CREATE ROLE dev_alice WITH LOGIN PASSWORD 'alice_dev_pass';
CREATE ROLE dev_bob WITH LOGIN PASSWORD 'bob_dev_pass';
CREATE ROLE dev_charlie WITH LOGIN PASSWORD 'charlie_dev_pass';

-- Establish hierarchy
GRANT junior_devs TO dev_alice, dev_bob;
GRANT senior_devs TO dev_charlie;
GRANT junior_devs TO senior_devs;
GRANT dev_team TO senior_devs;

-- Development database permissions
GRANT ALL PRIVILEGES ON DATABASE dev_environment TO dev_team;
GRANT CREATE ON SCHEMA public TO dev_team;

Security Best Practices and Advanced Configurations

Row-Level Security (RLS)

-- Enable RLS on sensitive tables
ALTER TABLE user_management.users ENABLE ROW LEVEL SECURITY;

-- Create policies for multi-tenant access
CREATE POLICY tenant_isolation ON user_management.users
    FOR ALL TO tenant_alpha_app
    USING (tenant_id = 'alpha');

CREATE POLICY tenant_beta_policy ON user_management.users
    FOR ALL TO tenant_beta_app
    USING (tenant_id = 'beta');

-- Admin bypass policy
CREATE POLICY admin_access ON user_management.users
    FOR ALL TO db_admin
    USING (true);

Connection and Resource Limits

-- Set connection limits per role
ALTER ROLE app_user CONNECTION LIMIT 20;
ALTER ROLE reports_readonly CONNECTION LIMIT 5;

-- Configure pg_hba.conf for IP-based restrictions
-- Add these lines to /etc/postgresql/[version]/main/pg_hba.conf:
# host    production_app    app_user    10.0.0.0/8    md5
# host    production_app    reports_readonly    192.168.1.0/24    md5

-- Reload configuration
SELECT pg_reload_conf();

Permission Auditing and Monitoring

Checking Current Permissions

-- View table permissions for a specific role
SELECT 
    schemaname,
    tablename,
    privilege_type,
    is_grantable
FROM information_schema.role_table_grants 
WHERE grantee = 'app_user';

-- Check schema permissions
SELECT 
    schema_name,
    privilege_type,
    is_grantable
FROM information_schema.schema_privileges 
WHERE grantee = 'developers';

-- View role inheritance chain
WITH RECURSIVE role_tree AS (
    SELECT oid, rolname, 0 as level
    FROM pg_roles 
    WHERE rolname = 'app_user'
    
    UNION ALL
    
    SELECT pr.oid, pr.rolname, rt.level + 1
    FROM pg_roles pr
    JOIN pg_auth_members am ON pr.oid = am.roleid
    JOIN role_tree rt ON am.member = rt.oid
)
SELECT level, rolname FROM role_tree;

Performance Monitoring Query

-- Monitor active connections by role
SELECT 
    usename,
    application_name,
    client_addr,
    state,
    query_start,
    query
FROM pg_stat_activity 
WHERE state = 'active'
ORDER BY query_start DESC;

Common Pitfalls and Troubleshooting

Issue Symptom Solution
Permission denied on table ERROR: permission denied for table users Grant explicit table permissions or check schema access
Cannot create objects ERROR: permission denied for schema public Grant CREATE privilege on target schema
Role cannot login FATAL: role “app_user” is not permitted to log in Add LOGIN attribute: ALTER ROLE app_user LOGIN;
Inherited permissions not working Access denied despite role membership Check if role has INHERIT attribute enabled

Debugging Permission Issues

-- Check if role has LOGIN privilege
SELECT rolname, rolcanlogin FROM pg_roles WHERE rolname = 'problematic_role';

-- Verify role membership
SELECT 
    r.rolname,
    array_agg(m.rolname) as member_of
FROM pg_roles r
LEFT JOIN pg_auth_members am ON r.oid = am.member
LEFT JOIN pg_roles m ON am.roleid = m.oid
WHERE r.rolname = 'app_user'
GROUP BY r.rolname;

-- Check table ownership and permissions
SELECT 
    t.schemaname,
    t.tablename,
    t.tableowner,
    array_agg(DISTINCT p.privilege_type) as privileges
FROM information_schema.tables t
LEFT JOIN information_schema.role_table_grants p 
    ON t.table_name = p.table_name 
    AND p.grantee = 'app_user'
WHERE t.schemaname = 'user_management'
GROUP BY t.schemaname, t.tablename, t.tableowner;

Performance Considerations and Optimization

When managing a large number of roles and permissions on your VPS, consider these performance implications:

  • Role hierarchy depth: Deep inheritance chains can slow down permission resolution
  • RLS policies: Complex row-level security policies add overhead to every query
  • Connection pooling: Use tools like PgBouncer to manage connection limits effectively
  • Permission caching: PostgreSQL caches permission lookups, but frequent role changes can invalidate caches
-- Monitor permission-related performance
SELECT 
    query,
    calls,
    total_time,
    mean_time,
    rows
FROM pg_stat_statements 
WHERE query LIKE '%pg_roles%' OR query LIKE '%pg_auth_members%'
ORDER BY total_time DESC;

For production environments requiring high availability, consider implementing these practices on dedicated servers where you can fine-tune PostgreSQL configurations and resource allocation for optimal permission management performance.

The official PostgreSQL documentation provides comprehensive details about the role system and security features at PostgreSQL User Management and PostgreSQL Privileges.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked