Managed Databases
Set up and manage PostgreSQL, MySQL, Redis, and MongoDB databases on DigitalOcean.
What you'll accomplish
A managed database connected to your application
Prerequisites
- DigitalOcean account
- Application deployed
DigitalOcean Managed Databases
Fully managed database clusters with:
- Automatic backups - Daily with point-in-time recovery
- High availability - Standby nodes and failover
- Scaling - Resize without downtime
- Security - Private networking, encryption
- Maintenance - Automatic updates
Available Engines
| Engine | Use Case | Starting Price |
|---|---|---|
| PostgreSQL | General purpose, complex queries | $15/mo |
| MySQL | Web applications, WordPress | $15/mo |
| Redis | Caching, sessions, queues | $15/mo |
| MongoDB | Document store, flexible schema | $15/mo |
| Kafka | Event streaming, logs | $99/mo |
Creating a Database
Via CLI
bash# PostgreSQL doctl databases create mydb \ --engine pg \ --version 16 \ --size db-s-1vcpu-1gb \ --region nyc1 \ --num-nodes 1 # MySQL doctl databases create mydb \ --engine mysql \ --version 8 \ --size db-s-1vcpu-1gb \ --region nyc1 # Redis doctl databases create myredis \ --engine redis \ --version 7 \ --size db-s-1vcpu-1gb \ --region nyc1 # MongoDB doctl databases create mymongo \ --engine mongodb \ --version 7 \ --size db-s-1vcpu-1gb \ --region nyc1
Via Control Panel
- Go to Databases → Create Database Cluster
- Choose engine (PostgreSQL, MySQL, etc.)
- Select version
- Choose size and region
- Configure nodes (1 for dev, 2+ for HA)
- Click Create
Database Sizes
| Size | vCPU | RAM | Storage | Price |
|---|---|---|---|---|
| db-s-1vcpu-1gb | 1 | 1 GB | 10 GB | $15/mo |
| db-s-1vcpu-2gb | 1 | 2 GB | 25 GB | $30/mo |
| db-s-2vcpu-4gb | 2 | 4 GB | 38 GB | $60/mo |
| db-s-4vcpu-8gb | 4 | 8 GB | 115 GB | $120/mo |
Connecting to Your Database
Get Connection Details
bash# Get connection info doctl databases connection DB_ID # Output includes: # Host, Port, User, Password, Database, URI
Connection String Formats
PostgreSQL:
postgresql://user:password@host:port/database?sslmode=require
MySQL:
mysql://user:password@host:port/database?ssl-mode=REQUIRED
Redis:
rediss://user:password@host:port
MongoDB:
mongodb+srv://user:password@host/database?tls=true&authSource=admin
Connect from Application
Node.js (PostgreSQL):
javascriptconst { Pool } = require('pg'); const pool = new Pool({ connectionString: process.env.DATABASE_URL, ssl: { rejectUnauthorized: false } });
Node.js (MySQL):
javascriptconst mysql = require('mysql2/promise'); const pool = mysql.createPool({ uri: process.env.DATABASE_URL, ssl: { rejectUnauthorized: false } });
Node.js (Redis):
javascriptconst Redis = require('ioredis'); const redis = new Redis(process.env.REDIS_URL);
Database Management
Create Database
bash# Create a database in the cluster doctl databases db create DB_CLUSTER_ID myappdb
Create User
bash# Create user doctl databases user create DB_CLUSTER_ID myuser # Get user info (includes password) doctl databases user get DB_CLUSTER_ID myuser
List Databases and Users
bash# List databases doctl databases db list DB_CLUSTER_ID # List users doctl databases user list DB_CLUSTER_ID
Connection Pooling (PostgreSQL)
Manage connections efficiently:
Enable Pooling
bash# Create connection pool doctl databases pool create DB_ID mypool \ --db defaultdb \ --user doadmin \ --size 10 \ --mode transaction
Pool Modes
| Mode | Description | Use Case |
|---|---|---|
transaction | Connection per transaction | Most apps |
session | Connection per session | Long transactions |
statement | Connection per statement | Simple queries |
Get Pool Connection
bashdoctl databases pool get DB_ID mypool
Use the pool URI instead of direct connection for better performance.
Security
Trusted Sources
Restrict access to specific IPs:
bash# Add trusted source doctl databases firewalls append DB_ID \ --rule droplet:DROPLET_ID # Or by IP doctl databases firewalls append DB_ID \ --rule ip_addr:1.2.3.4 # Or App Platform doctl databases firewalls append DB_ID \ --rule app:APP_ID
Private Networking
Use VPC for secure connections:
- Create database in same VPC as Droplets
- Use private hostname instead of public
- No encryption overhead (already private)
bash# Get private connection doctl databases connection DB_ID --format PrivateURI --no-header
High Availability
Standby Nodes
Add standby nodes for failover:
bash# Create with HA doctl databases create mydb \ --engine pg \ --size db-s-2vcpu-4gb \ --region nyc1 \ --num-nodes 2 # Primary + 1 standby
Read Replicas
Scale read operations:
bash# Add read replica doctl databases replica create DB_ID mydb-replica \ --size db-s-1vcpu-2gb \ --region nyc1
Use replica connection for read queries to reduce primary load.
Backups
Automatic Backups
- Daily automatic backups
- 7-day retention (default)
- Point-in-time recovery (PostgreSQL)
Restore from Backup
bash# Fork database from backup doctl databases create mydb-restored \ --engine pg \ --size db-s-1vcpu-1gb \ --region nyc1 \ --restore-from DB_ID \ --restore-from-time "2024-01-15 10:30:00"
Maintenance
Maintenance Windows
bash# Set maintenance window doctl databases maintenance-window update DB_ID \ --day sunday \ --hour 04:00
Version Upgrades
bash# Upgrade PostgreSQL version doctl databases update DB_ID --version 16
App Platform Integration
Dev Database (Free)
yaml# .do/app.yaml databases: - name: db engine: PG production: false # Free dev database
Production Database
yamldatabases: - name: db engine: PG production: true cluster_name: my-db-cluster db_name: myapp db_user: myuser
Reference in Service
yamlservices: - name: web envs: - key: DATABASE_URL scope: RUN_TIME value: ${db.DATABASE_URL}
Performance
Query Performance
Monitor slow queries in Control Panel:
- Database → Insights → Query Statistics
Index Recommendations
Check for missing indexes:
- Database → Insights → Index Advisor
Connection Management
Best practices:
- Use connection pooling
- Close connections properly
- Set appropriate pool sizes
- Monitor active connections
Migrations
Run Migrations
bash# Connect and run migrations DATABASE_URL="postgresql://..." npx prisma migrate deploy # Or with knex DATABASE_URL="postgresql://..." npx knex migrate:latest
Schema Changes
For zero-downtime migrations:
- Add new columns (nullable)
- Deploy code that writes to both old/new
- Migrate data
- Deploy code that uses new column
- Remove old column
Complete Example
PostgreSQL Setup
bash# Create database cluster DB_ID=$(doctl databases create myapp-db \ --engine pg \ --version 16 \ --size db-s-1vcpu-1gb \ --region nyc1 \ --output json | jq -r '.[0].id') echo "Database ID: $DB_ID" # Wait for database to be ready while true; do STATUS=$(doctl databases get $DB_ID --format Status --no-header) if [ "$STATUS" = "online" ]; then break fi echo "Waiting for database... ($STATUS)" sleep 10 done # Create application database doctl databases db create $DB_ID myapp # Create application user doctl databases user create $DB_ID appuser # Get connection string DATABASE_URL=$(doctl databases connection $DB_ID --format URI --no-header) echo "Connection: $DATABASE_URL" # Add trusted source (your app) doctl databases firewalls append $DB_ID \ --rule app:YOUR_APP_ID
Connect from App Platform
yaml# .do/app.yaml name: myapp region: nyc services: - name: web github: repo: username/myapp branch: main http_port: 3000 envs: - key: DATABASE_URL scope: RUN_TIME type: SECRET value: "postgresql://..." # From doctl output databases: - name: db engine: PG production: true
Troubleshooting
Connection Refused
- Check trusted sources include your app/IP
- Verify connection string is correct
- Check SSL mode is set
Too Many Connections
- Enable connection pooling
- Reduce pool size in app
- Close unused connections
- Upgrade database size
Slow Queries
- Check query statistics
- Add missing indexes
- Optimize query structure
- Consider read replicas
Connection Timeout
- Check network/firewall settings
- Verify private networking is configured
- Check database is online
Note
Checkpoint: Create a managed database, get the connection string, and successfully connect from your application.