MemosMemos
Configuration

Database Configuration

Configure and optimize database settings for your Memos instance.

Database Configuration

Memos supports multiple database backends to suit different deployment scenarios. This guide covers setup, configuration, and optimization for each supported database.

Supported Databases

Database Selection Guide

SQLite (Default)

Best for:

  • Single-user installations
  • Development environments
  • Small teams (< 10 users)
  • Simple deployment requirements

Advantages:

  • Zero configuration
  • File-based storage
  • High performance for read-heavy workloads
  • Built-in with Memos

Limitations:

  • Single writer at a time
  • No remote access
  • Limited concurrent users

Best for:

  • Multi-user production deployments
  • High-concurrency environments
  • Enterprise installations
  • Advanced querying needs

Advantages:

  • Excellent concurrent performance
  • Advanced indexing and querying
  • Full ACID compliance
  • Mature ecosystem

Requirements:

  • Separate PostgreSQL server
  • Additional maintenance overhead

MySQL/MariaDB

Best for:

  • Existing MySQL infrastructure
  • Specific MySQL expertise
  • Legacy system integration

Advantages:

  • Wide adoption and expertise
  • Good performance
  • Extensive tooling

Considerations:

  • Additional complexity vs SQLite
  • Less optimal than PostgreSQL for concurrent workloads

SQLite Configuration

Default Setup

SQLite works out of the box with zero configuration:

# No additional setup needed
memos
# Database file created automatically at: data/memos_prod.db

Custom SQLite Location

# Environment variable
export MEMOS_DATA="/custom/path/to/data"
memos

# Docker
docker run -v /host/path:/var/opt/memos neosmemo/memos:stable

# Docker Compose
services:
  memos:
    image: neosmemo/memos:stable
    volumes:
      - ./custom-data:/var/opt/memos

SQLite Optimization

Database Settings

-- Connect to SQLite database
sqlite3 /path/to/memos_prod.db

-- Optimize settings
PRAGMA journal_mode = WAL;
PRAGMA synchronous = NORMAL;
PRAGMA cache_size = 1000000;
PRAGMA temp_store = MEMORY;

Performance Tuning

# Set environment variables for better SQLite performance
export SQLITE_TMPDIR="/tmp"
export SQLITE_DEFAULT_CACHE_SIZE=1000000

SQLite Performance: For better performance with SQLite, ensure your data directory is on fast storage (SSD) and consider using WAL mode for better concurrent access.

PostgreSQL Configuration

Server Installation

Ubuntu/Debian

sudo apt update
sudo apt install postgresql postgresql-contrib

# Start service
sudo systemctl start postgresql
sudo systemctl enable postgresql

CentOS/RHEL

sudo yum install postgresql-server postgresql-contrib
sudo postgresql-setup initdb
sudo systemctl start postgresql
sudo systemctl enable postgresql

Docker PostgreSQL

version: '3.8'
services:
  postgres:
    image: postgres:15
    environment:
      POSTGRES_DB: memos
      POSTGRES_USER: memos
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  memos:
    image: neosmemo/memos:stable
    depends_on:
      - postgres
    environment:
      - MEMOS_DRIVER=postgres
      - MEMOS_DSN=postgresql://memos:${DB_PASSWORD}@postgres:5432/memos?sslmode=disable
    ports:
      - "5230:5230"

volumes:
  postgres_data:

Database Setup

-- Connect as postgres user
sudo -u postgres psql

-- Create database and user
CREATE DATABASE memos;
CREATE USER memos WITH ENCRYPTED PASSWORD 'your-secure-password';

-- Grant permissions
GRANT ALL PRIVILEGES ON DATABASE memos TO memos;

-- Connect to the database
\c memos

-- Grant schema permissions (PostgreSQL 15+)
GRANT ALL ON SCHEMA public TO memos;
GRANT ALL ON ALL TABLES IN SCHEMA public TO memos;
GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO memos;

-- Set default permissions for future objects
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO memos;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO memos;

\q

Connection Configuration

Environment Variables

export MEMOS_DRIVER=postgres
export MEMOS_DSN="postgresql://memos:password@localhost:5432/memos?sslmode=disable"

Docker Environment

docker run -d \
  --name memos \
  -p 5230:5230 \
  -e MEMOS_DRIVER=postgres \
  -e MEMOS_DSN="postgresql://memos:password@postgres:5432/memos?sslmode=disable" \
  neosmemo/memos:stable

PostgreSQL Optimization

Server Configuration

Edit /etc/postgresql/15/main/postgresql.conf:

# Memory settings
shared_buffers = 256MB
effective_cache_size = 1GB
maintenance_work_mem = 64MB
work_mem = 16MB

# Connection settings  
max_connections = 100
shared_preload_libraries = 'pg_stat_statements'

# Write-ahead logging
wal_buffers = 16MB
checkpoint_completion_target = 0.9

# Query optimization
random_page_cost = 1.1  # For SSD storage
effective_io_concurrency = 200

Performance Monitoring

-- Enable pg_stat_statements extension
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

-- Monitor slow queries
SELECT 
  query,
  calls,
  total_time,
  mean_time,
  rows
FROM pg_stat_statements 
ORDER BY total_time DESC 
LIMIT 10;

MySQL Configuration

Server Installation

Ubuntu/Debian

sudo apt update
sudo apt install mysql-server

# Secure installation
sudo mysql_secure_installation

# Start service
sudo systemctl start mysql
sudo systemctl enable mysql

Docker MySQL

version: '3.8'
services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: memos
      MYSQL_USER: memos
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${ROOT_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

  memos:
    image: neosmemo/memos:stable
    depends_on:
      - mysql
    environment:
      - MEMOS_DRIVER=mysql
      - MEMOS_DSN=memos:${DB_PASSWORD}@tcp(mysql:3306)/memos?charset=utf8mb4&parseTime=True&loc=Local
    ports:
      - "5230:5230"

volumes:
  mysql_data:

Database Setup

-- Connect as root
mysql -u root -p

-- Create database and user
CREATE DATABASE memos CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'memos'@'%' IDENTIFIED BY 'your-secure-password';
GRANT ALL PRIVILEGES ON memos.* TO 'memos'@'%';
FLUSH PRIVILEGES;

EXIT;

Connection Configuration

# Environment variables
export MEMOS_DRIVER=mysql
export MEMOS_DSN="memos:password@tcp(localhost:3306)/memos?charset=utf8mb4&parseTime=True&loc=Local"

Connection String Format

PostgreSQL DSN Examples

# Basic connection
postgresql://username:password@host:port/database

# With SSL
postgresql://username:password@host:port/database?sslmode=require

# Connection pooling
postgresql://username:password@host:port/database?pool_max_conns=10

# Full example
postgresql://memos:secretpass@localhost:5432/memos?sslmode=disable&connect_timeout=10

MySQL DSN Examples

# Basic connection  
username:password@tcp(host:port)/database

# With charset and timezone
username:password@tcp(host:port)/database?charset=utf8mb4&parseTime=True&loc=Local

# Connection limits
username:password@tcp(host:port)/database?charset=utf8mb4&maxOpenConns=10&maxIdleConns=5

# Full example
memos:secretpass@tcp(localhost:3306)/memos?charset=utf8mb4&parseTime=True&loc=Local&timeout=10s

Database Migrations

Automatic Migrations

Memos handles database schema migrations automatically:

# Migrations run on startup
2025/08/19 12:00:00 [INFO] Running database migrations...
2025/08/19 12:00:01 [INFO] Applied migration: 001_initial_schema
2025/08/19 12:00:01 [INFO] Applied migration: 002_add_user_settings
2025/08/19 12:00:01 [INFO] Database migrations completed

Manual Migration Control

# Skip migrations (not recommended)
export MEMOS_SKIP_MIGRATIONS=true

# Migration timeout (seconds)
export MEMOS_MIGRATION_TIMEOUT=300

Backup and Maintenance

SQLite Backup

# Simple file copy (while service is stopped)
cp /path/to/memos_prod.db /backup/location/

# Online backup using SQLite command
sqlite3 /path/to/memos_prod.db ".backup /backup/location/memos_backup.db"

# Compressed backup
sqlite3 /path/to/memos_prod.db ".dump" | gzip > backup.sql.gz

PostgreSQL Backup

# Database dump
pg_dump -h localhost -U memos -d memos > memos_backup.sql

# Compressed backup
pg_dump -h localhost -U memos -d memos | gzip > memos_backup.sql.gz

# Custom format (recommended)
pg_dump -h localhost -U memos -d memos -Fc > memos_backup.dump

# Automated backup script
#!/bin/bash
BACKUP_DIR="/backups/memos"
DATE=$(date +%Y%m%d_%H%M%S)
pg_dump -h localhost -U memos -d memos -Fc > "$BACKUP_DIR/memos_$DATE.dump"

MySQL Backup

# Database dump
mysqldump -u memos -p memos > memos_backup.sql

# Compressed backup
mysqldump -u memos -p memos | gzip > memos_backup.sql.gz

# All databases
mysqldump -u root -p --all-databases > all_databases_backup.sql

Monitoring and Troubleshooting

Connection Issues

Check Database Status

# PostgreSQL
sudo systemctl status postgresql
pg_isready -h localhost -p 5432

# MySQL  
sudo systemctl status mysql
mysqladmin -u memos -p ping

# SQLite
ls -la /path/to/data/
sqlite3 /path/to/memos_prod.db ".tables"

Test Connections

# PostgreSQL
psql -h localhost -U memos -d memos -c "SELECT version();"

# MySQL
mysql -h localhost -u memos -p -e "SELECT version();"

Performance Monitoring

Database Size Monitoring

-- PostgreSQL
SELECT 
  pg_size_pretty(pg_database_size('memos')) as db_size,
  pg_size_pretty(pg_total_relation_size('memos')) as table_size;

-- MySQL
SELECT 
  table_schema as 'Database',
  ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) as 'Size (MB)'
FROM information_schema.tables 
WHERE table_schema = 'memos';

Query Performance

-- PostgreSQL slow queries
SELECT 
  query,
  calls,
  total_time / calls as avg_time_ms
FROM pg_stat_statements 
WHERE calls > 100
ORDER BY avg_time_ms DESC
LIMIT 10;

-- MySQL slow queries  
SELECT * FROM mysql.slow_log 
ORDER BY start_time DESC 
LIMIT 10;

Production Reminder: Always test database configuration changes in a non-production environment first, and ensure you have proper backups before making any changes.

Security Considerations

Connection Security

  • Use strong passwords for database users
  • Enable SSL/TLS for remote connections
  • Restrict network access using firewalls
  • Regular security updates for database software
  • Monitor access logs for suspicious activity

Database Hardening

PostgreSQL Security

-- Remove public schema permissions
REVOKE ALL ON SCHEMA public FROM public;
GRANT USAGE ON SCHEMA public TO memos;

-- Limit connection attempts
ALTER SYSTEM SET log_connections = 'on';
ALTER SYSTEM SET log_disconnections = 'on';

MySQL Security

-- Remove anonymous users
DELETE FROM mysql.user WHERE User='';

-- Remove remote root access
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');

FLUSH PRIVILEGES;

Next Steps


Need help with database configuration? Check the troubleshooting guide or ask in GitHub Discussions.