psql, PostgreSQL ile gelen etkileşimli terminal istemcisidir: psql -h sunucu -p port -U kullanıcı -d veritabanı ile bağlanır, SQL komutlarını noktalı virgülle bitirerek çalıştırırsınız. Ters eğik çizgiyle başlayan meta komutları ise sunucu değil psql'in kendisi işler; en çok kullanılanları veritabanlarını listeleyen \l, tabloları listeleyen \dt, bir tablonun yapısını gösteren \d tablo, başka veritabanına geçen \c, dosya çalıştıran \i, geniş satırları alt alta gösteren \x ve süre ölçen \timing komutlarıdır.
Bu yazıda psql başvuru sayfasındaki bağlantı seçeneklerini, sık kullanılan meta komutları, psql değişkenlerini, betik çalıştırırken hata davranışını ve .psqlrc başlangıç dosyasını, her birini PostgreSQL 18.1 üzerinde çalıştırdığımız örneklerle anlatıyoruz. Örneklerin tamamı -X (başlangıç dosyasını okuma) ve -f ile verilen betiklerle çalıştırıldı; serinin diğer yazıları PostgreSQL öğrenme rehberi sayfasında. Çıktılarda yer kazanmak için CREATE ve INSERT gibi komutların onay satırlarını yer yer çıkardık; sorgu sonuçları ve hata mesajları olduğu gibidir.
Bağlanmak: seçenekler ve varsayılanlar
Bir veritabanına bağlanmak için dört bilgi gerekir: sunucu adresi, port, veritabanı kullanıcısı ve veritabanı adı. Bunlar sırasıyla -h, -p, -U ve -d seçenekleriyle verilir; seçeneğe ait olmayan ilk argüman veritabanı adı, ikincisi kullanıcı adı olarak yorumlanır. Belgeye göre adres verilmezse psql Unix sistemlerde yerel soket üzerinden, Windows'ta ise TCP ile localhost adresine bağlanır. Varsayılan port derleme sırasında belirlenir (genellikle 5432), varsayılan kullanıcı işletim sistemi kullanıcı adınızdır, varsayılan veritabanı da kullanıcı adıyla aynıdır. Sık bağlandığınız bir sunucu için PGHOST, PGPORT, PGUSER ve PGDATABASE ortam değişkenleri yazmayı azaltır; parolalar için de ~/.pgpass dosyası önerilir.
Bağlantı bilgileri tek bir bağlantı dizesiyle (conninfo) ya da URI ile de verilebilir; -d değeri bir bağlantı dizesiyse içindeki parametreler komut satırındaki çakışan seçenekleri ezer:
psql -h 127.0.0.1 -p 46410 -U postgres -d ornek_psql
psql "host=127.0.0.1 port=46410 dbname=ornek_psql user=postgres sslmode=disable"
psql postgresql://postgres@127.0.0.1:46410/ornek_psqlBağlandıktan sonra hangi sunucuya, hangi kullanıcıyla bağlı olduğunuzu \conninfo gösterir. PostgreSQL 18 sürüm notlarına göre bu komutun çıktısı tablo biçimine geçti ve daha fazla bilgi içeriyor:
\conninfo Connection Information
Parameter | Value
----------------------+------------
Database | ornek_psql
Client User | postgres
Host | 127.0.0.1
Server Port | 46410
Options |
Protocol Version | 3.0
Password Used | false
GSSAPI Authenticated | false
Backend PID | 90428
SSL Connection | false
Superuser | on
Hot Standby | off
(12 rows)Çıktıdaki Password Used | false satırı, bu deneme kümesinin yalnızca yerel testler için parolasız ayarlandığını gösteriyor; gerçek sunucularda bunu yapmayın. Belge, Client User alanının bağlantı anındaki kullanıcıyı, Superuser alanının ise o anki kullanıcının süper kullanıcı olup olmadığını gösterdiğini, ikisinin SET ROLE sonrasında farklılaşabileceğini belirtir. Oturum içinde başka bir veritabanına geçmek için \c veritabanı yazılır; başarısız bir \c etkileşimli kipte eski bağlantıyı korur ama betik içinde eski bağlantıyı kapatır, böylece betik yanlış veritabanında çalışmaya devam etmez.
Nesneleri listelemek: \l, \dn, \dt, \d, \du

Örnekler için ornek_psql veritabanında satis adlı bir şema, içinde bir musteri tablosu ve public şemasında bir urun tablosu oluşturduk:
CREATE SCHEMA satis;
CREATE TABLE satis.musteri (
id integer PRIMARY KEY,
ad text NOT NULL,
il text DEFAULT 'İstanbul'
);
INSERT INTO satis.musteri VALUES (1, 'Ayşe Yılmaz', 'İzmir'), (2, 'Mehmet Öztürk', DEFAULT), (3, 'Çağla Şen', NULL);
CREATE TABLE urun (kod text PRIMARY KEY, fiyat numeric(10,2));\dn
\dt
\dt satis.* List of schemas
Name | Owner
--------+-------------------
public | pg_database_owner
satis | postgres
(2 rows)
List of tables
Schema | Name | Type | Owner
--------+------+-------+----------
public | urun | table | postgres
(1 row)
List of tables
Schema | Name | Type | Owner
--------+---------+-------+----------
satis | musteri | table | postgres
(1 row)\dt neden musteri tablosunu göstermedi? Belgenin Patterns bölümüne göre desen verilmezse \d ailesi yalnızca arama yolunda (search_path) görünür olan nesneleri listeler; satis şeması arama yolunda olmadığı için tablo görünmez. Şema ile nesne adını nokta ile ayıran satis.* deseni, bütün şemalar için ise *.* deseni kullanılır. Desenlerde * herhangi bir karakter dizisine, ? tek karaktere karşılık gelir ve adlar SQL'deki gibi küçük harfe çevrilir; büyük harf korunsun istiyorsanız çift tırnak kullanırsınız. Arama yolunun nasıl çalıştığı veritabanı ve şema oluşturma yazısında.
\d satis.musteri Table "satis.musteri"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+------------------
id | integer | | not null |
ad | text | | not null |
il | text | | | 'İstanbul'::text
Indexes:
"musteri_pkey" PRIMARY KEY, btree (id)\d sütunları, tiplerini, NULL durumunu ve varsayılanları, altında da indeksleri, kısıtları ve tetikleyicileri gösterir; \d+ buna sütun açıklamalarını, depolama bilgisini ve view tanımını ekler. Komut harflerinin bir sistemi vardır: \dt tablo, \di indeks, \dv view, \dm materialized view, \ds sequence, \dE yabancı tablo listeler ve harfler birleştirilebilir (\dti tablo ve indeksleri birlikte listeler). Sonuna + eklemek ayrıntıyı, S eklemek sistem nesnelerini, x eklemek genişletilmiş görünümü açar.
\du List of roles
Role name | Attributes
-----------+------------------------------------------------------------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS| Komut | Ne gösterir veya yapar |
|---|---|
| \l veya \list | Veritabanları, sahipleri, kodlama, locale ve erişim yetkileri |
| \c ad | Başka bir veritabanına (veya kullanıcıyla) yeniden bağlanır |
| \dn | Şemalar |
| \dt, \di, \dv, \ds | Tablolar, indeksler, view ve sequence nesneleri |
| \d ad | Tek bir nesnenin sütunları, indeksleri, kısıtları |
| \df | Fonksiyonlar ve prosedürler |
| \du | Roller ve öznitelikleri |
| \dp veya \z | Tablo, view ve sequence erişim yetkileri |
| \dx | Kurulu eklentiler |
| \x | Genişletilmiş (alt alta) çıktıyı açar veya kapatır |
| \i dosya | Dosyadaki komutları klavyeden yazılmış gibi çalıştırır |
| \timing | Her komutun süresini milisaniye olarak gösterir |
| \h komut | SQL komutunun söz dizimi özeti |
| \? | Meta komutların listesi |
| \q | psql oturumunu kapatır |
Çıktıyı biçimlendirmek: \x, \pset ve \gx
Çok sütunlu bir satır terminale sığmadığında \x genişletilmiş görünümü açar ve her sütunu ayrı satırda gösterir. Tek bir sorgu için bunu kalıcı olarak açmak istemiyorsanız sorguyu noktalı virgül yerine \gx ile bitirirsiniz. \pset ise çıktı ayarlarını değiştirir; örneğin NULL değerlerin boş görünmesi yüzünden boş metinle karıştırılmasını önlemek için \pset null ile görünür bir işaret atayabilirsiniz:
\x on
SELECT * FROM satis.musteri WHERE id = 1;
\x off
\pset null '(boş)'
SELECT id, ad, il FROM satis.musteri ORDER BY id;Expanded display is on.
-[ RECORD 1 ]---
id | 1
ad | Ayşe Yılmaz
il | İzmir
Expanded display is off.
Null display is "(boş)".
id | ad | il
----+---------------+----------
1 | Ayşe Yılmaz | İzmir
2 | Mehmet Öztürk | İstanbul
3 | Çağla Şen | (boş)
(3 rows)İkinci müşteride DEFAULT yazdığımız için sütun varsayılanı olan İstanbul kullanıldı, üçüncüde ise açıkça NULL verdik. \x auto değeri, genişletilmiş görünümü yalnızca çıktı terminal genişliğine sığmadığında açar. \pset format ile aligned (varsayılan), unaligned, csv, html gibi biçimler seçilebilir; komut satırında aynı işi -A, --csv, -H seçenekleri, başlıksız tek değer almak için de -t görür. Betiklerden tek bir değer okumak için -At birleşimi kullanışlıdır:
psql -h 127.0.0.1 -p 46410 -U postgres -X -d ornek_psql -At -c "SELECT current_database(), current_user"ornek_psql|postgrespsql değişkenleri ve güvenli yer değiştirme
psql'in kendi değişkenleri vardır ve \set ad değer ile atanır; değer, önüne iki nokta konarak (:ad) hem SQL komutlarında hem meta komutlarda kullanılır. Belge burada önemli bir güvenlik ayrımı yapar: :ad biçimi değeri hiçbir tırnaklama yapmadan olduğu gibi kopyalar; değeri SQL metni olarak kullanmak için :'ad', tanımlayıcı (tablo veya sütun adı) olarak kullanmak için :"ad" yazmanız gerekir. Bu iki biçim, değerin içindeki tırnakları ve özel karakterleri doğru kaçışlar. Tırnaklı bir metnin içinde (':ad') yer değiştirme yapılmaz.
\set sehir 'İzmir'
\set tablo musteri
SELECT ad FROM satis.:"tablo" WHERE il = :'sehir'; ad
-------------
Ayşe Yılmaz
(1 row)Bir sorgunun sonucunu değişkene almak için sorguyu \gset ile bitirirsiniz; sorgu tam olarak bir satır döndürmelidir ve her sütun aynı adlı bir değişkene yazılır. NULL dönen sütunun değişkeni atanmak yerine silinir:
SELECT count(*) AS adet, max(id) AS son FROM satis.musteri \gset
\echo Toplam :adet müşteri, son id :sonToplam 3 müşteri, son id 3Bazı değişkenler özeldir ve büyük harfle yazılır: bağlantı bilgisini tutan DBNAME, USER, HOST, PORT; son sorgunun durumunu tutan ERROR, SQLSTATE, ROW_COUNT; davranışı değiştiren AUTOCOMMIT, ON_ERROR_STOP, ON_ERROR_ROLLBACK, ECHO, VERBOSITY, PROMPT1. Belge, kendi değişkenleriniz için tamamen büyük harfli adlardan kaçınmanızı önerir. Değişkenler komut satırında -v ad=değer ile de verilebilir. psql değişkenlerinin sunucu parametrelerini değiştiren SQL SET komutuyla bir ilgisi yoktur.
\gset ile \if birlikte kullanılınca betiklere koşul eklenebilir. Aşağıdaki betik, bir ürün kodunun var olup olmadığına bakıp yoksa ekliyor:
SELECT EXISTS (SELECT 1 FROM urun WHERE kod = 'Z9') AS var_mi \gset
\if :var_mi
\echo Z9 zaten var
\else
\echo Z9 yok, ekleniyor
INSERT INTO urun VALUES ('Z9', 99.90);
\endifZ9 yok, ekleniyor
INSERT 0 1Betik çalıştırmak: -f, \i ve hata davranışı

Bir dosyadaki komutları psql -f dosya.sql ile ya da oturum içinden \i dosya.sql ile çalıştırırsınız. Belge -f kullanımının psql < dosya.sql yönlendirmesine göre satır numaralı hata mesajları gibi avantajlar sağladığını belirtir. \ir ise göreli dosya adlarını o anki çalışma dizinine değil, çalışan betiğin bulunduğu dizine göre çözer; birbirini çağıran betiklerde bu fark önemlidir.
Asıl dikkat edilmesi gereken nokta hata davranışıdır. Varsayılan olarak psql bir komut hata verdiğinde sonraki komutlarla devam eder ve sonunda 0 koduyla çıkar. Aşağıdaki üç satırlık betikte ikinci satır birincil anahtar ihlali veriyor:
INSERT INTO urun VALUES ('A1', 10.50);
INSERT INTO urun VALUES ('A1', 12.00);
INSERT INTO urun VALUES ('B2', 7.25);psql -h 127.0.0.1 -p 46410 -U postgres -X -d ornek_psql -f hatali.sql; echo "exit=$?"INSERT 0 1
psql:hatali.sql:2: ERROR: duplicate key value violates unique constraint "urun_pkey"
DETAIL: Key (kod)=(A1) already exists.
INSERT 0 1
exit=0Üçüncü satır çalıştı ve dönüş kodu 0 oldu; bir otomasyon betiği bu çalıştırmayı başarılı sayardı. ON_ERROR_STOP değişkeni açıldığında psql ilk hatada durur ve betik modunda 3 koduyla çıkar. Tabloyu boşaltıp aynı dosyayı bu kez -v ON_ERROR_STOP=1 ile çalıştırdık:
psql -h 127.0.0.1 -p 46410 -U postgres -X -d ornek_psql -v ON_ERROR_STOP=1 -f hatali.sql; echo "exit=$?"INSERT 0 1
psql:hatali.sql:2: ERROR: duplicate key value violates unique constraint "urun_pkey"
DETAIL: Key (kod)=(A1) already exists.
exit=3Bu kez üçüncü satır çalışmadı ama ilk satırın eklediği kayıt tabloda kaldı. Ya hep ya hiç davranışı istiyorsanız -1 (--single-transaction) seçeneğini de ekleyin: psql bütün dosyayı tek bir BEGIN ve COMMIT arasına alır, ON_ERROR_STOP açıkken bir komut başarısız olursa COMMIT yerine ROLLBACK gönderir. Aynı denemeyi -1 -v ON_ERROR_STOP=1 ile yaptığımızda yine 3 kodu döndü ve SELECT count(*) FROM urun sorgusu 0 satır gösterdi; ilk ekleme de geri alınmıştı. Psql belgesi, dosyanın kendisi BEGIN, COMMIT veya transaction içinde çalışamayan bir komut içeriyorsa bu seçeneğin beklenen sonucu vermeyeceğini de belirtir. Transaction davranışının ayrıntıları ve ON_ERROR_ROLLBACK değişkeni transaction yazısında anlatılıyor.
| Dönüş kodu | Anlamı |
|---|---|
| 0 | Normal bitiş (ON_ERROR_STOP kapalıysa SQL hataları da 0 döndürebilir) |
| 1 | psql'in kendi ölümcül hatası, örneğin dosya bulunamadı |
| 2 | Etkileşimsiz oturumda sunucu bağlantısı koptu veya kurulamadı |
| 3 | Betikte hata oluştu ve ON_ERROR_STOP açıktı |
Hata ayıklama ve ölçüm: \errverbose, \timing, \watch
Son hatayı en ayrıntılı biçimde görmek için \errverbose yazılır; çıktı SQLSTATE kodunu ve hatanın sunucu kaynak kodundaki yerini de içerir. Aynı oturumda SQLSTATE ve ERROR değişkenleri de güncellenir:
SELECT * FROM olmayan_tablo;
\errverbose
\echo :SQLSTATE :ERRORpsql:psql2.sql:7: ERROR: relation "olmayan_tablo" does not exist
LINE 1: SELECT * FROM olmayan_tablo;
^
psql:psql2.sql:8: error: ERROR: 42P01: relation "olmayan_tablo" does not exist
LINE 1: SELECT * FROM olmayan_tablo;
^
LOCATION: parserOpenTable, parse_relation.c:1469
42P01 true42P01 gibi kodların anlamı ve çözümleri için SQLSTATE kodları yazısına bakın. \timing on her komuttan sonra süreyi yazdırır; ölçülen süre istemcinin gözünden toplam süredir. Bizim Windows denememizde ondalık ayırıcı virgül olarak göründü:
\timing on
SELECT count(*) FROM generate_series(1, 100000);Timing is on.
count
--------
100000
(1 row)
Time: 6,364 msSorgunun planını ve sunucu tarafındaki süreleri ayrıntılı görmek istiyorsanız \timing yerine EXPLAIN ANALYZE kullanın. \watch ise son sorguyu belirli aralıklarla tekrar çalıştırır; PostgreSQL 18 ile varsayılan bekleme süresini ayarlayan WATCH_INTERVAL değişkeni eklendi. i= aralığı, c= tekrar sayısını belirler:
SELECT count(*) AS urun_sayisi FROM urun \watch i=1 c=27.11.2026 12:25:31 (every 1s)
urun_sayisi
-------------
2
(1 row)
7.11.2026 12:25:32 (every 1s)
urun_sayisi
-------------
2
(1 row).psqlrc başlangıç dosyası
psql, -X verilmedikçe bağlandıktan sonra önce sistem genelindeki psqlrc dosyasını, ardından kullanıcının kişisel başlangıç dosyasını çalıştırır. Kişisel dosya Unix'te ev dizinindeki .psqlrc, Windows'ta %APPDATA%\postgresql\psqlrc.conf dosyasıdır ve yolu PSQLRC ortam değişkeniyle değiştirilebilir. Dosya adına -18 gibi bir sürüm eki eklenirse yalnızca o sürüm okur. Biz kullanıcının kendi dosyasına dokunmamak için PSQLRC ile geçici bir dosya gösterdik:
\set QUIET 1
\pset null '(null)'
\set PROMPT1 '%n@%/%R%# '
\set HISTCONTROL ignoredups
\timing on
\unset QUIETQUIET açıkken çalışan ayar komutları bilgi mesajı yazmaz, sonda kapatılarak normal davranışa dönülür. PROMPT1 içindeki %n kullanıcı adına, %/ veritabanı adına, %R psql'in durumuna, %# ise süper kullanıcı için #, diğerleri için > işaretine dönüşür. Komut istemine %x eklemek, açık bir transaction içinde *, hatalı bir transaction içinde ! göstererek unutulmuş transaction'ları fark etmenizi sağlar. Otomasyon betiklerinde kişisel ayarların sonucu değiştirmemesi için her zaman -X kullanın.
Sık yapılan hatalar

- Meta komutu noktalı virgülle bitirmek veya SQL ile aynı -c içinde karıştırmak: Bir
-cdeğeri ya sunucunun anlayacağı saf SQL ya da tek bir meta komut olmalıdır; ikisini birden çalıştırmak için-cseçeneğini tekrarlayın. - Tek -c içindeki birden çok SQL komutunun ayrı transaction olduğunu sanmak: Belgeye göre tek bir
-cdizesi sunucuya tek istek olarak gider ve içinde açıkBEGIN/COMMITyoksa tek transaction gibi çalışır. - Betiklerde ON_ERROR_STOP kullanmamak: Hata veren bir dağıtım betiği 0 koduyla bitebilir; CI ve cron işlerinde
-v ON_ERROR_STOP=1verin. - Değişkeni tırnaksız yerleştirmek: Kullanıcıdan gelen bir değeri
:adile SQL'e koymak tırnak kaçışı yapmaz; metin için:'ad', tanımlayıcı için:"ad"kullanın. - Görünmeyen tabloyu silinmiş sanmak:
\dtyalnızca arama yolundaki nesneleri listeler;\dt *.*veya\dt şema.*ile bakın. - Windows komut satırında Türkçe karakterli -c kullanmak: Bizim denememizde komut satırından verilen Türkçe karakterler kodlamayı bozdu; Türkçe içeren komutları UTF-8 bir dosyaya yazıp
-file çalıştırın.
Sık Sorulan Sorular
psql ile CSV dosyası nasıl içe aktarılır?
psql'in \copy meta komutu, dosyayı sunucunun değil sizin makinenizin dosya sisteminden okur ve süper kullanıcı yetkisi gerektirmez. Seçenekler SQL COPY komutuyla aynıdır; ayrıntılar ve örnekler COPY ile CSV içe ve dışa aktarma yazısında.
psql sürümü sunucu sürümüyle aynı olmalı mı?
Belge, psql'in aynı veya daha eski ana sürümdeki sunucularla en iyi çalıştığını söyler. Özellikle \d ailesi gibi meta komutlar, psql'den daha yeni bir sunucuda başarısız olabilir; farklı sürümlü sunuculara bağlanıyorsanız en yeni psql sürümünü kullanmanız önerilir.
Sorgunun hangi SQL ile çalıştığını, yani \d komutlarının arkasını görebilir miyim?
Evet. psql'i -E ile başlatırsanız ya da \set ECHO_HIDDEN on yazarsanız meta komutların sunucuya gönderdiği katalog sorguları ekrana yazdırılır. Bu, sistem kataloglarını öğrenmek için iyi bir yoldur.
Komut geçmişi nerede saklanır?
Unix sistemlerde ~/.psql_history, Windows'ta %APPDATA%\postgresql\psql_history dosyasında saklanır. Yolu HISTFILE değişkeni veya PSQL_HISTORY ortam değişkeniyle değiştirebilir, \s ile geçmişi görüntüleyebilirsiniz.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: PostgreSQL öğrenme rehberi · PostgreSQL kurulumu · Veritabanı ve şema oluşturma · Transaction yönetimi · COPY ile CSV aktarma · SQLSTATE hata kodları