Installs into .claude/skills of the current project.
Are you the author of Postgres Readonly Queries?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/huytran1120-postgres-readonly-queries)
---
name: postgres-readonly-queries
description: "Execute safe read-only SQL queries against PostgreSQL databases with multi-connection support and defense-in-depth write protection."
category: data
risk: critical
source: https://github.com/sanjay3290/ai-skills/tree/main/skills/postgres
source_repo: sanjay3290/ai-skills
source_type: community
date_added: "2026-07-09"
author: sanjay3290
tags: [postgres, sql, database, read-only]
tools: [claude, cursor, gemini]
license: "Apache-2.0"
license_source: "https://github.com/sanjay3290/ai-skills/blob/main/LICENSE"
---
# PostgreSQL Read-Only Query Skill
## When to Use
- Use when querying PostgreSQL databases and access must stay strictly read-only
- Use when exploring schemas, tables, and data across multiple configured connections
- Use when you want defense-in-depth protection against accidental INSERT/UPDATE/DELETE or DDL
Execute safe, read-only queries against configured PostgreSQL databases.
## Requirements
- Python 3.8+
- psycopg2-binary: `pip install -r requirements.txt`
## Setup
Create `connections.json` in the skill directory or `~/.config/claude/postgres-connections.json`.
**Security**: Set file permissions to `600` since it contains credentials:
```bash
chmod 600 connections.json
```
```json
{
"databases": [
{
"name": "production",
"description": "Main app database - users, orders, transactions",
"host": "db.example.com",
"port": 5432,
"database": "app_prod",
"user": "readonly_user",
"password": "your-password",
"sslmode": "verify-full"
}
]
}
```
### Config Fields
| Field | Required | Description |
|-------|----------|-------------|
| name | Yes | Identifier for the database (case-insensitive) |
| description | Yes | What data this database contains (used for auto-selection) |
| host | Yes | Database hostname |
| port | No | Port number (default: 5432) |
| database | Yes | Database name |
| user | Yes | Username |
| password | Yes | Password |
| sslmode | No | SSL mode: disable, allow, verify-full (default), require, verify-ca, verify-full |
## Usage
### List configured databases
```bash
python3 scripts/query.py --list
```
### Query a database
```bash
python3 scripts/query.py --db production --query "SELECT * FROM users LIMIT 10"
```
### List tables
```bash
python3 scripts/query.py --db production --tables
```
### Show schema
```bash
python3 scripts/query.py --db production --schema
```
### Limit results
```bash
python3 scripts/query.py --db production --query "SELECT * FROM orders" --limit 100
```
## Database Selection
Match user intent to database `description`:
| User asks about | Look for description containing |
|-----------------|--------------------------------|
| users, accounts | users, accounts, customers |
| orders, sales | orders, transactions, sales |
| analytics, metrics | analytics, metrics, reports |
| logs, events | logs, events, audit |
If unclear, run `--list` and ask user which database.
## Safety Features
- **Read-only session**: Connection uses PostgreSQL `readonly=True` mode (primary protection)
- **Query validation**: Conservative keyword/semicolon checks, not a SQL parser or authorization boundary
- **Single statement**: Multiple statements per query rejected
- **SSL support**: Configurable SSL mode for encrypted connections
- **Query timeout**: 30-second statement timeout enforced
- **Display cap**: At most 10,000 rows printed; the client/server may still buffer or compute a much larger result
- **Column width cap**: 100 char max per column for readable output
- **Credential sanitization**: Error messages don't leak passwords
## Troubleshooting
| Error | Solution |
|-------|----------|
| Config not found | Create `connections.json` in skill directory |
| Authentication failed | Check username/password in config |
| Connection timeout | Verify host/port, check firewall/VPN |
| SSL error | Check certificate hostname, root CA and server TLS configuration; do not disable verification to bypass errors |
| Permission warning | Run `chmod 600 connections.json` |
## Exit Codes
- **0**: Success
- **1**: Error (config missing, auth failed, invalid query, database error)
## Workflow
1. Run `--list` to show available databases
2. Match user intent to database description
3. Run `--tables` or `--schema` to explore structure
4. Execute query with appropriate LIMIT
## Limitations
- Read-only protections reduce accidental writes but cannot override database-server policy,
triggers, extensions, or an over-privileged account. Use a database role with read-only
permissions as the primary control.
- Query results can contain personal, confidential, or regulated data. Confirm the intended
database and avoid exporting or sharing results without explicit authorization.
- The script is not a replacement for backups, auditing, access reviews, or production change
controls.
Use `bash` only for shell examples and `python3 scripts/query.py` for the inert helper. Keep credential config outside version control, restrict file permissions before adding credentials, and never print values. `--limit` caps displayed rows without rewriting SQL; include a reviewed SQL LIMIT for server-side work where appropriate. Keyword/semicolon checks reject some valid SQL and cannot prevent SELECT function side effects, external calls or all temporary writes. Read-only privileges and a trusted, restricted function environment are essential. `EXPLAIN ANALYZE` actually executes its query. Python buffering and large individual values can still exhaust memory; use a dedicated bounded reporting query.