psql ist der mit PostgreSQL ausgelieferte Kommandozeilen-Client — und in der Praxis das wichtigste Werkzeug, um eine Postgres-Datenbank im Detail zu erkunden. Im Vergleich zu GUI-Tools ist psql schnell, überall verfügbar und versteht viele Aufgaben über kurze Meta-Commands. Dieser Artikel deckt das Wichtigste ab: Verbindung, Schema-Erkundung, Output-Formatierung, kleine Komfort-Tricks und ein sinnvolles ~/.psqlrc.
Verbindung herstellen
psql versteht eine Reihe von Connection-Flags. Die wichtigsten:
| Flag | Wirkung | Default |
|---|---|---|
-h <host> | Hostname / Socket | Lokaler Unix-Socket |
-p <port> | Port | 5432 |
-U <user> | Postgres-Rolle | Aktueller Shell-User |
-d <db> | Ziel-Datenbank | Gleicher Name wie -U |
-W | Passwort interaktiv erzwingen | aus pg_hba.conf abgeleitet |
Typische Aufrufe:
# Lokal als aktueller User in die Datenbank "myapp"
psql myapp
# Expliziter User und Datenbank ueber TCP
psql -h localhost -U app -d myapp
# Remote-Server
psql -h db.example.com -U app -d myappAlternativ als Connection-URI in einem einzigen Argument:
psql "postgresql://app:secret@localhost:5432/myapp"Praktisch fürs Kopieren aus Tools wie Doppler, .env oder dem Cloud-Dashboard.
Passwort sicher hinterlegen: in ~/.pgpass mit Format host:port:db:user:password, Permissions chmod 600. psql liest die Datei automatisch und braucht dann kein -W.
Eingabe-Modi und Beenden
Im interaktiven Modus zeigt psql einen Prompt mit Datenbankname:
myapp=#Das # signalisiert, dass du als Superuser verbunden bist; ein normaler User sieht =>. Mehrzeilige Statements werden bis zum abschließenden ; gesammelt; der Prompt wechselt zu myapp-# bzw. myapp-(>, solange ein Statement offen ist.
Beenden des Clients:
\qOder schlicht mit Ctrl+D.
Meta-Commands — die Backslash-Welt
Alles, was mit Backslash beginnt, ist ein psql-eigener Befehl, kein SQL. Die wichtigsten Familien:
Hilfe und Übersicht
| Command | Wirkung |
|---|---|
\? | Hilfe zu allen Meta-Commands |
\h | Hilfe zu SQL-Statements (z. B. \h CREATE TABLE) |
\l | Liste aller Datenbanken im Cluster |
\du | Liste aller Rollen mit Attributen (\du+ zeigt zusätzliche Spalten) |
\dn | Liste aller Schemas |
Schema-Erkundung
| Command | Wirkung |
|---|---|
\d | Alle Relationen (Tabellen, Views, Sequenzen) im aktuellen Schema |
\d <name> | Detail-Beschreibung einer Relation: Spalten, Indexe, FKs, Trigger |
\dt | Nur Tabellen |
\dv | Nur Views |
\dm | Nur Materialized Views |
\df | Funktionen |
\df+ <name> | Funktion inkl. Quelltext |
\di | Indexe |
\ds | Sequenzen |
\dx | Installierte Extensions |
\dp <name> | Privilegien auf Relation |
Ein einzelnes + am Ende vieler Commands (\d+, \df+, \dt+) zeigt zusätzliche Spalten — Größe, Beschreibung, Storage-Optionen.
Datenbank wechseln
\c andere_db
\c andere_db andere_user\c baut eine neue Connection auf — die alte wird geschlossen. Nützlich, wenn man im selben psql-Prozess zwischen mehreren Datenbanken springen will.
Output-Formatierung
Bei Tabellen mit vielen Spalten oder breiten Werten wird die Default-Tabellen-Ansicht schnell unleserlich. psql hat dafür Schalter:
| Command | Wirkung |
|---|---|
\x | Erweiterte Anzeige (eine Spalte pro Zeile) — toggle |
\x auto | Automatisch erweitert, wenn die Zeile nicht passt |
\pset format aligned|unaligned|csv|json | Output-Format |
\pset null '∅' | Anzeige von NULL-Werten |
\pset linestyle unicode | Hübschere Tabellenränder |
\pset border 2 | Mehr Tabellenränder |
Beispiel: \x auto mit Output in Markdown-tauglichem Stil:
myapp=# \x auto
myapp=# SELECT * FROM users WHERE id = 1;
-[ RECORD 1 ]----+----------------------
id | 1
email | alice@example.com
created_at | 2026-04-01 10:23:14+00
last_login_at | 2026-05-05 18:02:11+00Kleine Komfort-Tricks
\timing — Query-Dauer messen
myapp=# \timing
Timing is on.
myapp=# SELECT count(*) FROM events;
count
--------
184223
Time: 24.117 msSehr nützlich, um schnell ein Gefühl für Query-Performance zu bekommen. Für seriöses Profiling bleibt EXPLAIN ANALYZE das Mittel der Wahl.
\e — Statement im Editor öffnen
Öffnet den letzten Query-Buffer in $EDITOR. Beim Speichern und Schließen wird das Statement ausgeführt. Praktisch für längere SQL-Stücke, ohne dass man eine separate Datei anlegt.
\watch <sek> — Query wiederholen
myapp=# SELECT count(*) FROM jobs WHERE status='pending';
myapp=# \watch 5Führt die letzte Query alle 5 Sekunden erneut aus — ein simples Live-Dashboard auf der CLI.
\copy — schnelle Datenübernahme
Im Gegensatz zu COPY (das auf dem Server läuft und Server-Pfade braucht) liest \copy lokal:
myapp=# \copy users FROM 'users.csv' WITH (FORMAT csv, HEADER true);
myapp=# \copy (SELECT * FROM users) TO 'export.csv' WITH (FORMAT csv, HEADER true);\gexec — Output als nächstes SQL ausführen
Zwei-Schritt-Pattern: erst eine Query, die Statements erzeugt, dann \gexec führt jeden zurückgegebenen Wert als eigenes Statement aus:
SELECT format('DROP TABLE IF EXISTS %I CASCADE;', tablename)
FROM pg_tables
WHERE schemaname = 'public' AND tablename LIKE 'tmp_%' \gexec~/.psqlrc — psql persönlicher machen
psql lädt beim Start ~/.psqlrc. Damit kannst du sinnvolle Defaults setzen:
\set QUIET 1
\pset null '∅'
\pset linestyle unicode
\pset border 2
\x auto
\timing
\set HISTFILE ~/.psql_history- :DBNAME
\set HISTSIZE 5000
\set PROMPT1 '%[%033[1;32m%]%n@%/%[%033[0m%]%R%# '
\set PROMPT2 '%[%033[1;32m%]%/%[%033[0m%]%R%# '
\unset QUIETWas passiert hier: NULL wird sichtbar (∅), Tabellen kriegen Unicode-Ränder, \x auto schaltet bei breiten Zeilen automatisch auf erweiterte Ansicht, \timing ist immer an, der Prompt zeigt User und DB, und die History wird pro Datenbank getrennt — sehr praktisch, wenn du regelmäßig auf mehreren DBs arbeitest.
Besonderheiten
\d ist die schnellste Schema-Doku, die es gibt.
Es zeigt Spalten mit Typen, NOT-NULL und Defaults, alle Indexe (inkl. UNIQUE und Partial), Foreign Keys ein- und ausgehend, Trigger, Check-Constraints und Inheritance. Schneller als jedes ER-Diagramm — und immer aktuell, weil direkt aus dem Katalog.
\h liefert die SQL-Syntax direkt aus der Doku.
\h CREATE TABLE zeigt die komplette BNF-Syntax aus der offiziellen PostgreSQL-Doku, inkl. Link am Ende. Wenn du nur kurz nachsehen willst, ob eine Klausel RETURNING heißt oder OUTPUT, ist das schneller als ein Browser-Tab.
\copy läuft auf dem Client, COPY auf dem Server.
COPY users FROM '/path/to/file' erwartet die Datei am Server-Filesystem und braucht Superuser-Rechte. \copy liest und schreibt mit den Rechten des psql-Aufrufers — meistens das, was du wirklich willst. Aufpassen: in Skripten immer \copy, nicht COPY.
\g und \gexec sind Killer-Features für SQL-Generierung.
\g führt das aktuelle Statement nochmal mit anderen Parametern aus, \gexec führt das Ergebnis als SQL aus. Damit kannst du Refactorings („alle Tabellen mit Suffix _old droppen”), Bulk-Statements aus dem Katalog oder Code-Generation komplett in psql machen — ohne externe Skript-Sprache.
\watch macht psql zum Mini-Live-Dashboard.
Für eine schnelle Auge-darauf-Halten-Schicht — Queue-Tiefe, langsame Sessions, Replikations-Lag — reicht oft <Query> + \watch 2. Kein Grafana, kein Datadog, kein Tab-Switch. Beendet wird es mit Ctrl+C.
Variablen in psql: \set, :variable, :'variable', :"variable".
psql kennt eigene Variablen, die nichts mit SQL-Variablen zu tun haben. \set tbl users definiert eine; :tbl ersetzt sie roh, :'tbl' als String-Literal, :"tbl" als Identifier. Praktisch für wiederverwendbare Skripte: SELECT count(*) FROM :"tbl";.
Weiterführende Ressourcen
Externe Quellen
- psql – PostgreSQL Documentation
- Connection URIs – PostgreSQL Documentation
- The Password File (.pgpass)
- COPY – PostgreSQL Documentation
- Tip: ~/.psqlrc Tweaks – PostgreSQL Wiki