This README provides a complete template for PostgreSQL database connection setup and privilege management.
- Environment Setup
- Database Connection
- Privilege Management
- Common Queries
- Usage Examples
- Troubleshooting
# Database Configuration
DB_HOST=localhost
DB_PORT=5432
DB_NAME=your_database_name
DB_USER=your_username
DB_PASSWORD=your_password
# Optional: SSL Configuration
DB_SSL=falsenpm install pg dotenvimport pkg from "pg";
const { Pool } = pkg;
import dotenv from "dotenv";
dotenv.config();
// Debug environment variables (remove in production)
console.log(`
Database Configuration:
- Host: ${process.env.DB_HOST}
- Port: ${process.env.DB_PORT}
- Database: ${process.env.DB_NAME}
- User: ${process.env.DB_USER}
- Password: ${process.env.DB_PASSWORD ? '***' : 'Not set'}
`);
const pool = new Pool({
host: process.env.DB_HOST || "localhost",
port: process.env.DB_PORT || 5432,
database: process.env.DB_NAME || "postgres",
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
// Optional pool configuration
max: 20, // Maximum number of clients in pool
idleTimeoutMillis: 30000, // Close idle clients after 30 seconds
connectionTimeoutMillis: 2000, // Return error if connection takes longer than 2 seconds
});
// Connection event handlers
pool.on("connect", () => {
console.log("✅ Connected to PostgreSQL database");
});
pool.on("error", (err) => {
console.error("❌ Unexpected error on idle client", err);
process.exit(-1);
});
// Test connection on startup
pool.connect((err, client, release) => {
if (err) {
console.error("❌ Error acquiring client", err.stack);
} else {
console.log("🔗 Database connection pool initialized");
release();
}
});
// Wrapper for queries
export const query = (text, params) => pool.query(text, params);
// Export pool for advanced usage
export { pool };
// Graceful shutdown
process.on('SIGINT', () => {
console.log('🔄 Gracefully shutting down database connections...');
pool.end(() => {
console.log('✅ Database pool has ended');
process.exit(0);
});
});-- Create new database
CREATE DATABASE your_database_name;
-- Create new user/role
CREATE USER your_username WITH PASSWORD 'your_password';
-- Grant connection privileges
GRANT CONNECT ON DATABASE your_database_name TO your_username;
-- Grant usage on schema
GRANT USAGE ON SCHEMA public TO your_username;-- Grant all privileges on all tables in schema
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO your_username;
-- Grant privileges on future tables
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO your_username;
-- Specific table privileges
GRANT SELECT, INSERT, UPDATE, DELETE ON table_name TO your_username;
-- Read-only access
GRANT SELECT ON ALL TABLES IN SCHEMA public TO your_username;-- For auto-incrementing IDs - Grant usage and select on sequence
GRANT USAGE, SELECT ON SEQUENCE users_id_seq TO your_username;
-- For updating sequence values
GRANT USAGE, SELECT, UPDATE ON SEQUENCE users_id_seq TO your_username;
-- Full control over sequence
GRANT ALL PRIVILEGES ON SEQUENCE users_id_seq TO your_username;
-- Grant on all sequences
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO your_username;
-- Grant on future sequences
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO your_username;-- Execute privileges on functions
GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO your_username;
-- Grant on future functions
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT EXECUTE ON FUNCTIONS TO your_username;-- Create objects in schema
GRANT CREATE ON SCHEMA public TO your_username;
-- All privileges on schema
GRANT ALL ON SCHEMA public TO your_username;-- List all users
SELECT usename FROM pg_user;
-- Check user privileges
SELECT * FROM information_schema.role_table_grants WHERE grantee = 'your_username';
-- Drop user (must revoke privileges first)
REVOKE ALL PRIVILEGES ON DATABASE your_database_name FROM your_username;
DROP USER your_username;
-- Change password
ALTER USER your_username PASSWORD 'new_password';-- List all databases
SELECT datname FROM pg_database;
-- List all tables
SELECT tablename FROM pg_tables WHERE schemaname = 'public';
-- List all sequences
SELECT sequencename FROM pg_sequences WHERE schemaname = 'public';
-- Check table permissions
SELECT * FROM information_schema.table_privileges WHERE table_schema = 'public';-- Check active connections
SELECT pid, usename, application_name, client_addr, state
FROM pg_stat_activity
WHERE state = 'active';
-- Database size
SELECT pg_size_pretty(pg_database_size('your_database_name'));
-- Table sizes
SELECT
tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;import { query, pool } from './db/connection.js';
// Simple query
async function getUsers() {
try {
const result = await query('SELECT * FROM users');
return result.rows;
} catch (error) {
console.error('Error fetching users:', error);
throw error;
}
}
// Parameterized query
async function getUserById(id) {
try {
const result = await query('SELECT * FROM users WHERE id = $1', [id]);
return result.rows[0];
} catch (error) {
console.error('Error fetching user:', error);
throw error;
}
}
// Transaction example
async function transferFunds(fromAccount, toAccount, amount) {
const client = await pool.connect();
try {
await client.query('BEGIN');
await client.query(
'UPDATE accounts SET balance = balance - $1 WHERE id = $2',
[amount, fromAccount]
);
await client.query(
'UPDATE accounts SET balance = balance + $1 WHERE id = $2',
[amount, toAccount]
);
await client.query('COMMIT');
console.log('✅ Transaction completed successfully');
} catch (error) {
await client.query('ROLLBACK');
console.error('❌ Transaction failed:', error);
throw error;
} finally {
client.release();
}
}// Enhanced query wrapper with error handling
export const safeQuery = async (text, params = []) => {
const client = await pool.connect();
try {
const start = Date.now();
const result = await client.query(text, params);
const duration = Date.now() - start;
console.log(`Query executed in ${duration}ms`);
return result;
} catch (error) {
console.error('Database query error:', {
query: text,
params: params,
error: error.message
});
throw error;
} finally {
client.release();
}
};-
Connection refused
# Check if PostgreSQL is running sudo systemctl status postgresql # Start PostgreSQL sudo systemctl start postgresql
-
Authentication failed
- Verify username/password in
.env - Check
pg_hba.conffor authentication method - Ensure user has connection privileges
- Verify username/password in
-
Permission denied
-- Grant necessary privileges GRANT ALL PRIVILEGES ON DATABASE your_database_name TO your_username;
-
Too many connections
-- Check connection limit SHOW max_connections; -- Kill idle connections SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle' AND pid <> pg_backend_pid();
-
DB_HOST- Database host (default: localhost) -
DB_PORT- Database port (default: 5432) -
DB_NAME- Database name -
DB_USER- Database username -
DB_PASSWORD- Database password
- Never commit
.envfiles - Add to.gitignore - Use environment-specific configurations
- Implement connection pooling - Already included in template
- Use parameterized queries - Prevents SQL injection
- Limit user privileges - Follow principle of least privilege
- Enable SSL in production
- Regular backup and monitoring
# 1. Initialize project
npm init -y
npm install pg dotenv
# 2. Create directories
mkdir db config
# 3. Copy connection code to db/connection.js
# 4. Create and configure .env file
# 5. Test connection
node -e "import('./db/connection.js')"Note: Replace placeholder values (your_database_name, your_username, etc.) with your actual database credentials and configuration.