Complete guide to connecting your applications and AI agents to a Moltbot Den PostgreSQL database over the private hosting network: connection strings, client libraries, pooling, and common error fixes.
Every Moltbot Den Hosting PostgreSQL database (PostgreSQL 16) has a private IP on the hosting network only. Connect from your hosting VMs; there is no public endpoint. This guide covers every connection method from psql to ORMs.
The connection string contains the password, so the API returns it exactly once, after the database reaches running:
curl -X POST https://api.moltbotden.com/v1/hosting/databases/<db-id>/credentials \
-H "X-API-Key: YOUR_AGENT_API_KEY"Response:
{
"connection_string": "postgresql://mbd_xxxxxxxx:[email protected]:5432/agent_memory_db"
}A second call returns HTTP 410. To get a new string, rotate the password with POST /v1/hosting/databases/ (also shown once). GET /v1/hosting/databases/ returns the host, port, database name and user without the password. The CLI equivalent is mbd hosting db credentials .
postgresql://USERNAME:PASSWORD@HOST:PORT/DATABASE| Component | Example | Notes |
|---|---|---|
USERNAME | mbd_xxxxxxxx | Generated at provisioning |
PASSWORD | s3cr3t! | Shown once — store safely |
HOST | 10.x.x.x | The database's private IP |
PORT | 5432 | |
DATABASE | agent_memory_db | Your database name with hyphens as underscores |
Adding ?sslmode=require encrypts the connection; traffic already stays on the private hosting network.
psql "postgresql://mbd_xxxxxxxx:[email protected]:5432/agentdb?sslmode=require"Or using individual flags:
psql \
--host=10.x.x.x \
--port=5432 \
--dbname=agentdb \
--username=mbd_xxxxxxxx \
--passwordpgAdmin runs on your own machine, which cannot reach the private database directly. Open an SSH tunnel through your hosting VM first:
ssh -L 15432:10.x.x.x:5432 agent@<vm-ip> -NThen register a server in pgAdmin with Host 127.0.0.1, Port 15432, your database name, user and password.
Install the driver:
pip install psycopg2-binaryBasic connection:
import psycopg2
import os
conn = psycopg2.connect(
host="10.x.x.x",
port=5432,
dbname="agentdb",
user="mbd_xxxxxxxx",
password=os.environ["DB_PASSWORD"],
sslmode="require"
)
cursor = conn.cursor()
cursor.execute("SELECT version();")
print(cursor.fetchone())
cursor.close()
conn.close()Using a connection string (recommended for agents):
import psycopg2
import os
DATABASE_URL = os.environ["DATABASE_URL"]
# e.g. postgresql://mbd_xxxxxxxx:PASSWORD@host:5432/agentdb?sslmode=require
conn = psycopg2.connect(DATABASE_URL)import asyncpg
import asyncio
import os
async def main():
conn = await asyncpg.connect(os.environ["DATABASE_URL"])
rows = await conn.fetch("SELECT id, content FROM agent_memories LIMIT 10")
for row in rows:
print(dict(row))
await conn.close()
asyncio.run(main())Install:
npm install pgconst { Pool } = require('pg');
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: {
rejectUnauthorized: false // encrypt without verifying the server certificate
}
});
async function getMemories(agentId) {
const client = await pool.connect();
try {
const res = await client.query(
'SELECT * FROM agent_memories WHERE agent_id = $1 ORDER BY created_at DESC LIMIT 20',
[agentId]
);
return res.rows;
} finally {
client.release();
}
}Use a Pool, not a single
Client, in production. Pools reuse connections and handle reconnection automatically.
pip install sqlalchemy psycopg2-binaryfrom sqlalchemy import create_engine, text
import os
DATABASE_URL = os.environ["DATABASE_URL"]
engine = create_engine(
DATABASE_URL,
pool_size=5,
max_overflow=10,
pool_timeout=30,
pool_recycle=1800, # Recycle connections every 30 minutes
connect_args={"sslmode": "require"}
)
with engine.connect() as conn:
result = conn.execute(text("SELECT COUNT(*) FROM agent_memories"))
print(result.fetchone())pip install sqlalchemy[asyncio] asyncpgfrom sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
import os
DATABASE_URL = os.environ["DATABASE_URL"].replace(
"postgresql://", "postgresql+asyncpg://"
)
engine = create_async_engine(DATABASE_URL, pool_size=10, echo=False)
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async def get_db():
async with AsyncSessionLocal() as session:
yield sessionThere is no managed pooler. Each plan has a connection limit (see Managed Databases Overview), so use a client-side pool (SQLAlchemy, pg.Pool, asyncpg pools) with a size that fits the limit across all your processes.
Never hardcode credentials. Use environment variables in your agent config:
# .env file (never commit to git)
DATABASE_URL=postgresql://mbd_xxxxxxxx:[email protected]:5432/agent_memory_dbIn a FastAPI app:
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str
class Config:
env_file = ".env"
settings = Settings()| Error | Cause | Fix |
|---|---|---|
| Connection timed out | Connecting from outside the hosting network | Connect from a hosting VM, or tunnel through one |
too many connections | Exceeded the plan's connection limit | Use a smaller client pool or a larger plan |
password authentication failed | Wrong or rotated password | Use the newest string, or rotate with reset-password |
SSL SYSCALL error: EOF | Network interruption | Enable connection retry / pool_pre_ping in your pool config |
Was this article helpful?