How to Fix PostgreSQL Error: Database System is Starting Up

The "Database system is starting up" error occurs when attempting to connect to PostgreSQL while it is still initializing after being started. This is a temporary state that occurs during normal startup, especially after crashes or during recovery.

Impact

This error temporarily prevents database connections, causing brief application unavailability during PostgreSQL startup. It's normal during restarts and usually resolves within seconds to minutes.

Common Causes

  1. PostgreSQL is still starting up
  2. Database recovery in progress
  3. Crash recovery running
  4. Large shared_buffers initialization
  5. WAL replay during startup
  6. Extension initialization
  7. Very large database taking time to initialize

Troubleshooting and Resolution Steps

  1. Wait for startup to complete:

    # Check PostgreSQL status
    sudo systemctl status postgresql
    
    # Watch logs for startup progress
    sudo tail -f /var/log/postgresql/postgresql-15-main.log
    
    # Look for "database system is ready to accept connections"
    
  2. Implement connection retry logic:

    # Python with exponential backoff
    import psycopg2
    import time
    
    def connect_with_retry(max_attempts=10, initial_delay=0.5):
        for attempt in range(max_attempts):
            try:
                conn = psycopg2.connect(
                    "host=localhost dbname=mydb user=myuser password=pass"
                )
                print("Connected successfully")
                return conn
            except psycopg2.OperationalError as e:
                if 'starting up' in str(e).lower():
                    if attempt < max_attempts - 1:
                        delay = initial_delay * (2 ** attempt)
                        print(f"Database starting up, waiting {delay}s...")
                        time.sleep(delay)
                        continue
                raise
    
        raise Exception("Could not connect after maximum attempts")
    
    conn = connect_with_retry()
    
  3. Check startup progress:

    -- Once connected, check recovery status
    SELECT pg_is_in_recovery();
    
    -- Check for active recovery processes
    SELECT * FROM pg_stat_wal_receiver;
    
    -- View startup progress in logs
    -- Look for messages like:
    -- "database system was shut down at..."
    -- "redo starts at..."
    -- "database system is ready to accept connections"
    
  4. Application connection pooler configuration:

    # PgBouncer config - handle startup gracefully
    [pgbouncer]
    server_connect_timeout = 30
    server_check_delay = 10
    server_check_query = SELECT 1
    server_lifetime = 3600
    server_idle_timeout = 600
    
  5. Docker/Kubernetes health checks:

    # Docker Compose
    services:
      postgres:
        image: postgres:15
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U postgres"]
          interval: 10s
          timeout: 5s
          retries: 5
          start_period: 60s  # Allow time for startup
    
    # Kubernetes
    livenessProbe:
      exec:
        command:
          - /bin/sh
          - -c
          - pg_isready -U postgres
      initialDelaySeconds: 30
      periodSeconds: 10
      timeoutSeconds: 5
      failureThreshold: 6
    
  6. Check for crash recovery:

    # Look for crash recovery messages in logs
    sudo grep -i "crash\|recovery\|checkpoint" /var/log/postgresql/postgresql-15-main.log
    
    # Check for unclean shutdown
    # If database was not shut down cleanly, recovery will run
    
  7. Optimize startup time:

    -- Reduce shared_buffers if startup is slow
    -- In postgresql.conf
    shared_buffers = 1GB  -- Lower value starts faster
    
    -- Disable unnecessary extensions that slow startup
    -- Comment out in postgresql.conf
    # shared_preload_libraries = 'pg_stat_statements'  # If not needed
    
    -- Reload config (requires restart for these settings)
    SELECT pg_reload_conf();
    
  8. Monitor startup time:

    # Time PostgreSQL startup
    time sudo systemctl restart postgresql
    
    # Check logs for startup duration
    sudo grep "database system is ready" /var/log/postgresql/postgresql-15-main.log
    
  9. Application-level health check:

    # Simple health check endpoint
    from flask import Flask, jsonify
    import psycopg2
    
    app = Flask(__name__)
    
    @app.route('/health')
    def health():
        try:
            conn = psycopg2.connect(
                "host=localhost dbname=mydb",
                connect_timeout=5
            )
            cursor = conn.cursor()
            cursor.execute("SELECT 1")
            cursor.close()
            conn.close()
            return jsonify({"status": "healthy"}), 200
        except psycopg2.OperationalError as e:
            if 'starting up' in str(e).lower():
                return jsonify({"status": "starting"}), 503
            return jsonify({"status": "unhealthy", "error": str(e)}), 503
    
  10. Graceful degradation:

    # Handle startup gracefully in application
    class DatabaseConnection:
        def __init__(self):
            self.conn = None
            self.retry_delay = 1
    
        def connect(self):
            if self.conn:
                return self.conn
    
            try:
                self.conn = psycopg2.connect(...)
                self.retry_delay = 1  # Reset delay on success
                return self.conn
            except psycopg2.OperationalError as e:
                if 'starting up' in str(e).lower():
                    print("Database starting, will retry...")
                    time.sleep(self.retry_delay)
                    self.retry_delay = min(self.retry_delay * 2, 30)
                    return None
                raise
    
    # Usage
    db = DatabaseConnection()
    while not db.connect():
        # Serve cached data or show maintenance page
        pass
    

Additional Information

  • Normal startup usually completes in seconds
  • Crash recovery can take minutes for large databases
  • Retry logic is essential for production applications
  • Health checks should account for startup time
  • Monitor startup logs for issues
  • Large shared_buffers increases startup time slightly
  • Extensions in shared_preload_libraries affect startup time

Frequently Asked Questions

Q: How long should I wait for PostgreSQL to start?
A: Normal startup: 1-10 seconds. Crash recovery: seconds to minutes depending on database size and activity since last checkpoint.

Q: Is this error normal during restart?
A: Yes, completely normal. PostgreSQL needs time to initialize before accepting connections.

Q: How do I make startup faster?
A: Reduce shared_buffers, minimize shared_preload_libraries, ensure clean shutdowns, regular checkpoints.

Q: Should my application crash if it sees this error?
A: No, implement retry logic with exponential backoff. This is a temporary state.

Q: How do I know when startup is complete?
A: Check logs for "database system is ready to accept connections" or use pg_isready command.

Q: Can I connect as superuser during startup?
A: No, nobody can connect until startup completes, not even superusers.

Q: What if startup takes more than 5 minutes?
A: Check logs for errors, disk I/O issues, or extensive crash recovery. May indicate problems.

Q: How do containers handle this?
A: Use health checks with initialDelaySeconds and retries to wait for startup before marking container ready.

Pulse - Elasticsearch Operations Done Right

Pulse can solve your Elasticsearch issues

Subscribe to the Pulse Newsletter

Get early access to new Pulse features, insightful blogs & exclusive events , webinars, and workshops.

We use cookies to provide an optimized user experience and understand our traffic. To learn more, read our use of cookies; otherwise, please choose 'Accept Cookies' to continue using our website.