The most useful thing you can wire into Claude Code isn’t a new model or a clever prompt — it’s your actual database. When Claude Code can read your schema, it stops guessing at table names, column types, and relationships. It starts writing queries that work the first time.
This is the practical walkthrough for connecting Claude Code to a Postgres database via MCP: the command, the credential setup, the safety pattern, and what the workflow actually looks like once it’s running.
What the Postgres MCP server does
The official @modelcontextprotocol/server-postgres package (maintained in the MCP reference implementations repo) gives Claude Code four tools: schema inspection, query execution inside a read-only transaction, table detail lookup, and relationship traversal. The server cannot write data — it’s read-only by design in the reference implementation, though third-party variants like postgres-mcp-pro add configurable write access if you need it.
For the majority of development workflows — debugging, writing migrations, generating queries — read-only is exactly what you want. Claude Code can see the shape of your data without being able to touch it.
The fastest path: single command setup
If you just want it running against a local database:
claude mcp add postgres -- npx -y @modelcontextprotocol/server-postgres "postgresql://USER:PASSWORD@localhost:5432/mydb"
The -y flag on npx auto-accepts the package install so the command doesn’t hang on first run. Verify with:
claude mcp list
You should see postgres with a connected status. That’s it — Claude Code now has schema access in the current project.
Don’t do this for a production database. The connection string above is hardcoded. It goes into ~/.claude.json as plaintext. Use a dedicated local or staging database during development, and use env vars for anything that matters.
The right way: env vars and a read-only user
Two things to do before connecting to any real database:
1. Create a read-only Postgres user:
CREATE USER claude_readonly WITH PASSWORD 'your-password-here';
GRANT CONNECT ON DATABASE your_db TO claude_readonly;
GRANT USAGE ON SCHEMA public TO claude_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO claude_readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO claude_readonly;
This user can see everything in public and do nothing else. If something goes wrong — a rogue tool call, a compromised session — blast radius is zero.
2. Reference the connection string via env var in .mcp.json:
{
"mcpServers": {
"db": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"POSTGRES_CONNECTION_STRING": "${DATABASE_URL}"
}
}
}
}
Set DATABASE_URL in your shell environment or in a .env file (not committed). Add .mcp.json to the repo — everyone on the team gets the same server config — but the actual connection string lives in each developer’s local environment. This is the same pattern you already use for application config. It’s the right pattern here too.
Add the server at project scope so it’s committed:
claude mcp add --scope project --transport stdio db -- npx -y @modelcontextprotocol/server-postgres
Then edit .mcp.json to replace the hardcoded connection string with the ${DATABASE_URL} env var reference shown above.
What Claude Code can actually do with schema access
Once the server is connected, the workflow changes significantly. A few real examples:
Schema exploration: Ask Claude Code “what tables are in this database and how are they related?” and it traverses foreign keys, describes join paths, and builds a mental model of your data layer. No more copy-pasting \dt output.
Query generation: “Write a query that finds users who signed up in the last 30 days but haven’t completed onboarding” produces accurate SQL because Claude Code knows your actual column names. With a generic prompt and no schema access, you’d get plausible-looking SQL that fails because user_status is actually onboarding_state.
Migration drafting: “I need to add a last_login_at column to users — show me the migration and check for existing timestamp patterns in the schema.” Claude Code inspects the schema first, matches your existing column naming conventions, and produces a migration that fits your codebase.
Debugging: “This query is returning the wrong count — here’s the query, check it against the schema.” Claude Code can spot that you’re joining on a nullable column, missing a filter on a soft-delete flag, or aggregating before filtering.
Neon and cloud Postgres
If you’re on Neon, there’s a first-party MCP server with additional capabilities: branch management, database creation, and schema migrations via Neon’s branching model. Set it up with:
npx neonctl mcp add
This runs OAuth through your browser and configures Claude Code automatically. The Neon MCP server is intended for local development and IDE workflows — not production automation — same caution applies.
Debugging when it doesn’t connect
Three commands for when the server shows as disconnected:
claude mcp list # check registered servers and status
claude mcp test db # test a specific server
claude --debug # tail logs including MCP stderr output
Most connection failures are either a wrong connection string, a missing env var, or Node version issues with npx. The debug log shows the exact error from the server process — read it before assuming the problem is Claude Code.
The practical baseline
Five minutes to set up. The productivity delta on any codebase larger than a few tables is immediate — Claude Code stops making column-name mistakes and starts being genuinely useful for data-layer work. Wire up the read-only user, commit the .mcp.json, and add DATABASE_URL to your team’s .env.example. Done.
The model doing the work in a typical Claude Code session is claude-sonnet-4-6 (workhorse) — it handles schema-aware query generation well without burning through Opus 4.8 credits on every lookup.
Related Reading
- How to Connect Any Tool to Claude with MCP: Complete Setup Guide
- Notion MCP Setup with Claude: Complete Config + Undocumented Errors
- Claude Code vs Codex CLI (2026): A Hands-On Head-to-Head
- Claude Code vs Cursor in 2026: An Honest Comparison
- Always Allow vs Allow Once: Claude Code’s Quiet Tell
- Beyond llms.txt: Why AI Agents Crawl llms-full.txt More
- The AI Operator’s Stack: Running a Multi-Brand Content Machine
Frequently Asked Questions
How do I connect Claude Code to a Postgres database via MCP?
Run: claude mcp add postgres — npx -y @modelcontextprotocol/server-postgres “postgresql://USER:PASSWORD@localhost:5432/mydb”. The -y flag auto-accepts the package install so the command doesn’t hang. Then run claude mcp list and confirm postgres shows a connected status. Use a local or staging database for this quick path, not production.
Is the Postgres MCP server read-only?
Yes. The official @modelcontextprotocol/server-postgres package is read-only by design — it exposes schema inspection, query execution inside a read-only transaction, table detail lookup, and relationship traversal. It cannot write data. Third-party variants like postgres-mcp-pro add configurable write access if you need it.
What’s the safe way to connect Claude Code to a production database?
Create a dedicated read-only Postgres user (GRANT SELECT only), and reference the connection string through an environment variable in .mcp.json using ${DATABASE_URL} rather than hardcoding it. Commit .mcp.json so the team shares the server config, but keep the actual connection string in each developer’s local .env. If a session is ever compromised, the blast radius is zero.
Why does schema access make Claude Code more accurate?
With schema access, Claude Code reads your real table names, column types, and relationships, so it writes queries that work the first time instead of guessing. Without it, you get plausible-looking SQL that fails because user_status is actually onboarding_state. It also improves migration drafting and query debugging by matching your existing conventions.
How do I debug a Postgres MCP server that won’t connect?
Use three commands: claude mcp list to check registered servers and status, claude mcp test db to test a specific server, and claude –debug to tail logs including MCP stderr. Most failures are a wrong connection string, a missing env var, or a Node version issue with npx — the debug log shows the exact server error.





