SQL security manages database access through users (individual accounts), roles (named groups of permissions), and privileges (specific actions allowed on specific objects). GRANT gives privileges to a user or role. REVOKE removes them. Row-Level Security (RLS) restricts which rows a user can see within a table. Proper database security follows the principle of least privilege — users get only the permissions they need for their job, nothing more. Critical for production databases handling sensitive data.
Users, roles, and the least-privilege principle
Creating users and roles in PostgreSQL
-- CREATE USER (creates a login account)
CREATE USER api_user WITH PASSWORD 'SecurePass123!';
CREATE USER reporting_user WITH PASSWORD 'Reports2024!';
CREATE USER admin_user WITH PASSWORD 'AdminPass!' CREATEDB CREATEROLE;
-- Attributes that control login capabilities:
-- SUPERUSER / NOSUPERUSER: full admin access (avoid granting this!)
-- CREATEDB: can create databases
-- CREATEROLE: can create other roles
-- LOGIN / NOLOGIN: can this account log in?
-- CONNECTION LIMIT n: max concurrent connections (-1 = unlimited)
-- CREATE ROLE (like a group — typically no LOGIN by default)
CREATE ROLE readonly; -- Group role: no login, just permission grouping
CREATE ROLE readwrite;
CREATE ROLE finance_team;
CREATE ROLE app_backend;
-- GRANT role to user (assign group membership)
GRANT readonly TO reporting_user;
GRANT readwrite TO api_user;
GRANT finance_team TO reporting_user;
GRANT app_backend TO api_user;
-- A user inherits all privileges of their assigned roles
-- reporting_user has: readonly + finance_team permissionsGRANT and REVOKE privileges
Complete GRANT/REVOKE reference
-- GRANT: give privileges
-- Syntax: GRANT privilege ON object TO user/role
-- TABLE privileges
GRANT SELECT ON Employee TO readonly; -- Read only
GRANT SELECT, INSERT, UPDATE ON Orders TO readwrite; -- Read + write
GRANT ALL PRIVILEGES ON Product TO admin_user; -- Full control
-- Grant on all tables in schema
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
-- Auto-grant on future tables too (PostgreSQL)
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO readonly;
-- Specific column-level privileges (PostgreSQL/SQL Server)
GRANT SELECT (EmpID, Name, DeptID) ON Employee TO reporting_user;
-- reporting_user can query EmpID, Name, DeptID but NOT Salary or SSN!
-- Grant with GRANT OPTION (allows the grantee to grant to others)
GRANT SELECT ON Product TO team_lead WITH GRANT OPTION;
-- DATABASE-level privileges
GRANT CONNECT ON DATABASE mydb TO api_user;
GRANT CREATE ON DATABASE mydb TO admin_user;
-- SCHEMA-level privileges
GRANT USAGE ON SCHEMA public TO readonly; -- Can see objects in schema
GRANT CREATE ON SCHEMA public TO dev_user; -- Can create objects
-- FUNCTION / PROCEDURE privileges
GRANT EXECUTE ON FUNCTION GetEmployeeGrade(INT) TO api_user;
-- REVOKE: remove privileges
REVOKE INSERT ON Orders FROM readwrite; -- Remove specific privilege
REVOKE ALL PRIVILEGES ON Employee FROM reporting_user; -- Remove all
REVOKE GRANT OPTION FOR SELECT ON Product FROM team_lead; -- Remove grant option only
-- Check current privileges
SELECT grantee, privilege_type, table_name
FROM information_schema.role_table_grants
WHERE table_name = 'employee';
-- PostgreSQL: show all grants on a table
dp employeeRow-Level Security (RLS)
Row-Level Security — each user sees only their data
-- RLS: restrict which rows a user can read/modify
-- Use case: SaaS multi-tenant database — each tenant only sees their own data
-- 1. Enable RLS on the table
ALTER TABLE Orders ENABLE ROW LEVEL SECURITY;
-- 2. Create policies defining which rows are visible
-- Policy: each user can only see orders belonging to their company
CREATE POLICY tenant_isolation ON Orders
USING (tenant_id = current_setting('app.current_tenant_id')::INT);
-- Policy: managers can see all orders; staff only see their own
CREATE POLICY manager_sees_all ON Employee
USING (
current_user = 'hr_manager' -- HR manager sees everything
OR EmpID = (SELECT EmpID FROM UserMapping WHERE Username = current_user)
);
-- Policy: sales reps can only UPDATE their own opportunities
CREATE POLICY sales_rep_update ON Opportunity
FOR UPDATE
USING (assigned_to = current_user)
WITH CHECK (assigned_to = current_user);
-- BYPASSRLS: superusers bypass RLS (for admin operations)
ALTER USER admin_user BYPASSRLS;
-- Set the tenant context when connecting (app-level)
SET app.current_tenant_id = '42';
SELECT * FROM Orders; -- Only returns orders where tenant_id = 42
-- View: alternative to RLS for simpler cases
CREATE VIEW MyOrders AS
SELECT * FROM Orders WHERE CustomerID = current_user_id();
GRANT SELECT ON MyOrders TO customer_role;| Privilege level | Object | Privilege | Description |
|---|---|---|---|
| Database | DATABASE | CONNECT, CREATE, TEMP | Can connect/create objects/temp tables in database |
| Schema | SCHEMA | USAGE, CREATE | Can see objects / create objects in schema |
| Table | TABLE | SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES | DML operations on the table |
| Column | COLUMN | SELECT, INSERT, UPDATE | Access specific columns only |
| Function | FUNCTION | EXECUTE | Can call the function |
| Sequence | SEQUENCE | USAGE, SELECT, UPDATE | Can use auto-increment sequences |
Practice questions
- Difference between GRANT SELECT ON Employee TO user1 and GRANT SELECT (Name, DeptID) ON Employee TO user1: (Answer: First grants access to ALL columns of Employee. Second grants access to ONLY Name and DeptID columns — SELECT * still works but shows only those two columns. Column-level grants enable fine-grained access control for sensitive data like Salary, SSN, DOB.)
- What is the principle of least privilege in database security? (Answer: Users and applications should have ONLY the minimum permissions needed for their specific function. An API that only reads product data should have SELECT on Products only — not INSERT, UPDATE, DELETE, or access to Employee/Customer tables. Reduces damage if credentials are compromised.)
- REVOKE SELECT ON Employee FROM readonly — does this affect users with the readonly role? (Answer: Yes — if the privilege was granted to the readonly role, revoking it from the role removes it from all users who have that role. If a user also has SELECT granted directly, they retain it.)
- What is Row-Level Security used for? (Answer: RLS restricts which rows each user can see/modify within a table, without creating separate tables or views. Used for multi-tenant SaaS (each tenant sees only their data), departmental data access (HR sees only their department), or any scenario where row visibility depends on the user.)
- WITH GRANT OPTION — what does it mean? (Answer: Allows the grantee to grant the same privilege to others. GRANT SELECT ON Employee TO team_lead WITH GRANT OPTION means team_lead can also do: GRANT SELECT ON Employee TO other_user. Be careful — this creates chains of privilege that are hard to revoke fully.)
On LumiChats
LumiChats can design a complete permission matrix for your database, write all GRANT/REVOKE statements for a multi-role application, and implement Row-Level Security policies for multi-tenant scenarios. Describe your user types and data access requirements.
Try it free