SSL-Fehler nur in Produktion: SSL-Modus-Inkompatibilitäten beheben
SSL-Fehler in Produktion entstehen oft durch unterschiedliche SSL-Modi oder fehlende Zertifikate. Erfahre die typischen Fehler im Connection-String und wie du lokal testen kannst.

Warum SSL-Fehler der Datenbank nur in Produktion auftreten
SSL-Fehler der Datenbank, die nur in Produktion auftreten, bedeuten meist, dass deine App nicht mit derselben Art von Datenbank-Setup verbindet wie lokal. Dein Code kann identisch sein, aber in Produktion gelten andere Regeln für Netzwerk und Sicherheit.
Auf dem Laptop läuft Postgres oft auf localhost, manchmal in Docker, und unverschlüsselte TCP-Verbindungen sind erlaubt. In Produktion steht ein verwalteter Postgres-Dienst typischerweise hinter einem Load Balancer, Proxy oder Connection-Pooler, erzwingt Verschlüsselung und erwartet einen bestimmten SSL-Modus.
Wenn ein gehosteter Datenbankdienst „SSL erforderlich“ sagt, verweigert er unverschlüsselte Verbindungen. Einige Provider gehen weiter und verlangen zusätzlich die Zertifikatsprüfung. Genau hier unterscheiden sich Einstellungen wie sslmode=require vs sslmode=verify-full: require verschlüsselt die Verbindung, während verify-full zusätzlich das Serverzertifikat prüft und sicherstellt, dass der Hostname übereinstimmt.
Auch ohne Code-Änderungen kann das Verhalten unterschiedlich sein, weil Konfiguration und Defaults variieren. Deine lokale .env-Datei enthält möglicherweise keine SSL-Parameter, während Produktions-Umgebungsvariablen sie enthalten (oder deine Plattform sie injiziert). Manche Treiber haben standardmäßig prefer (erst SSL versuchen, dann zurückfallen), was lokal unauffällig funktioniert, in Produktion aber scheitern kann, wenn strikte Prüfung verlangt wird.
Netzwerkdetails ändern sich ebenfalls. Produktionsverbindungen laufen oft über einen Proxy, PgBouncer oder einen privaten Endpunkt. Das kann den Hostnamen ändern, zu dem du dich verbindest, und damit auch das präsentierte Zertifikat. Ein Connection-String mit einer IP kann unter require funktionieren, unter verify-full aber fehlschlagen, weil Zertifikate selten auf rohe IPs ausgestellt werden.
Typische Symptome sind Fehler wie:
- „SSL is required“ oder „no pg_hba.conf entry for host ... SSL off"
- „certificate verify failed“, „unable to get local issuer certificate“ oder „self signed certificate"
- „hostname mismatch“ oder „certificate does not match host"
- Funktioniert lokal und in Preview, schlägt aber nach dem Deployment gegen die Produktionsdatenbank fehl
- Intermittierende Fehler, wenn ein Pooler oder Proxy zwischengeschaltet ist
Ein realistisches Beispiel: lokal verbindest du dich mit postgres://localhost:5432/app ohne SSL-Einstellungen. In Produktion stellt dein verwalteter DB-Dienst eine URL wie postgres://user:[email protected]:5432/app?sslmode=verify-full bereit. Wenn deine App den Parameter weglässt (oder sslmode=disable verwendet), lehnt Produktion die Verbindung ab, obwohl dieselben Abfragen lokal funktionierten.
Erste 10 Minuten: den genauen Fehler und Kontext erfassen
Der schnellste Weg zur Lösung ist, zu stoppen mit Raten und den genauen Fehler zu erfassen. Kleine Details in der Fehlermeldung, dem Host und dem Ausführungsort des Codes weisen meist direkt auf die Ursache hin.
Kopiere den vollständigen Fehltext, inklusive aller „caused by“-Zeilen, und notiere das genaue Zeitfenster. Wenn du zentrale Logs hast, filtere um diesen Zeitstempel, um zu sehen, was kurz vor dem Fehler passiert ist.
Notiere als Nächstes, wo die Verbindung geöffnet wird. Eine Verbindung, die während einer Web-Request entsteht, kann sich anders verhalten als eine, die in einem Hintergrund-Worker, einer Serverless-Funktion oder einem geplanten Job erzeugt wird. Prüfe auch, ob sie sofort fehlschlägt oder erst nach einer Weile. „Funktioniert eine Weile, dann tot“ deutet oft auf Pooling, Timeouts oder etwas, das rotiert (Zertifikate, Routen oder Endpunkte).
Erfasse diese Basics, bevor du etwas änderst:
- Voller Fehltext und Stacktrace (die erste Fehlermeldung, nicht die letzte Retry-Meldung)
- Zeitfenster und Request- oder Job-ID (falls vorhanden)
- Laufzeitort (Webserver, Serverless, Cron, Queue-Worker)
- Ob es sofort fehlschlägt oder nur nach einigen erfolgreichen Abfragen
- Der Datenbank-Host, zu dem du tatsächlich verbindest
Der letzte Punkt ist besonders wichtig. Viele Apps haben mehrere Datenbank-URLs (Env-Variablen, Secret-Manager, hardcodierte Defaults, Preview-Umgebungen). Logge den aufgelösten Host zur Laufzeit (ohne Credentials). Wenn Produktion zu einem anderen Host verbindet als du denkst, haben dessen SSL-Anforderungen und Zertifikate möglicherweise andere Eigenschaften.
Prüfe auch, ob es in allen Produktionsregionen oder nur in einer Region fehlschlägt. Ein Ein-Region-Problem kann auf einen anderen Endpunkt, einen anderen Netzwerkpfad oder eine andere Zertifikatskette hindeuten.
SSL-Modi in einfachen Worten (und warum sie wichtig sind)
Die meisten Produktions-SSL-Fehler lassen sich auf Uneinigkeit darüber zurückführen, wie strikt die Verbindung sein soll. Lokale Datenbanken erlauben oft unverschlüsselte Verbindungen oder „Best-Effort“-SSL. Verwaltetes Postgres erzwingt meist SSL.
SSL hat zwei Aufgaben, die man trennen sollte:
- Verschlüsselung: schützt den Traffic, sodass niemand Passwörter oder Daten auf dem Weg mitlesen kann.
- Identitätsprüfung: beweist, dass du mit dem echten Datenbankserver sprichst.
Der „SSL-Modus“ steuert, wie streng du bei diesen beiden Aufgaben vorgehst.
Die gängigen SSL-Modi
Bei Postgres-Treibern und -Tools findest du meist:
- disable: niemals SSL verwenden
- prefer: erst SSL versuchen, bei Fehlschlag auf unverschlüsselt zurückfallen
- require: immer SSL-Verschlüsselung verwenden, aber die Server-Identität nicht streng prüfen
- verify-ca: SSL verwenden und prüfen, ob das Zertifikat zu einer vertrauenswürdigen CA gehört
- verify-full: SSL verwenden, CA prüfen und sicherstellen, dass der Hostname mit dem Zertifikat übereinstimmt
Wenn du einen strengen Modus wie verify-full setzt, aber nicht die richtige Zertifikatskette oder den passenden Hostnamen hast, bekommst du trotzdem SSL-Fehler — obwohl die Verbindung verschlüsselt ist.
Hostname-Validierung: die häufige Produktionsfalle
Hostname-Validierung bedeutet, dass das Serverzertifikat zum Host passen muss, zu dem du dich verbindest. Wenn dein Connection-String eine interne Adresse, eine IP oder einen anderen DNS-Namen verwendet als das Zertifikat, schlägt verify-full fehl. Das passiert oft, wenn Produktion dich durch einen Proxy oder privaten Endpunkt routet.
Defaults unterscheiden sich je nach Treiber (und das ist wichtig)
Treiber haben unterschiedliche Defaults. Der eine verhält sich standardmäßig wie prefer, ein anderer wie require, und dein Cloud-Provider könnte unverschlüsselte Verbindungen komplett ablehnen.
Bevor du etwas änderst, beantworte diese Fragen:
- Erzwingt Produktion SSL oder erlaubt sie unverschlüsselte Verbindungen?
- Verwendest du
requireoderverify-full? - Wenn du
verify-fullnutzt: stimmt der Host im Connection-String mit dem Zertifikat überein? - Woher kommt das CA-Zertifikat in Produktion (Datei, Env-Var, System-Trust-Store)?
- Testet deine lokale Umgebung tatsächlich denselben Modus oder fällt sie stillschweigend zurück?
Häufige Fehler im Connection-String, die Probleme verursachen
Produktions-SSL-Probleme sind meist kleine Inkonsistenzen zwischen dem, was die Produktion erwartet, und dem, was deine App wirklich sendet.
1) Falscher Parametername für deinen Treiber
Verschiedene Treiber lesen unterschiedliche SSL-Einstellungen. Manche achten auf sslmode, andere auf ssl=true, und einige erwarten ein Objekt statt eines Strings. Wenn du den falschen Namen benutzt, ignoriert der Treiber die Einstellung und fällt auf ein Default zurück.
Das kommt besonders oft in KI-generierten Projekten vor, weil Code-Beispiele aus verschiedenen Ökosystemen vermischt werden. Du siehst vielleicht sslMode an einer Stelle und sslmode an einer anderen. Das eine wird respektiert, das andere ignoriert.
2) Falsche Strenge (require vs verify-full)
Zwei Muster tauchen häufig auf:
- Du setzt
sslmode=require, aber dein Provider erwartet Zertifikatsprüfung (verify-caoderverify-full). - Du setzt
sslmode=verify-full, aber Hostname oder Zertifikatskette passen nicht zusammen, sodass Produktion scheitert, während lokal schwächere Einstellungen ausreichen.
3) Fehlendes CA-Zertifikat bei verify-ca oder verify-full
Wenn du Zertifikate verifizierst, brauchst du meist ein CA-Zertifikat (z. B. via sslrootcert oder eine treiberspezifische Option). Ohne dieses siehst du Fehler wie „self signed certificate“, „unable to get local issuer certificate“ oder „certificate verify failed“.
Ein einfaches Beispiel dessen, was häufig gemeint ist (Namen variieren je nach Treiber):
... sslmode=verify-full sslrootcert=/path/to/ca.pem
4) Verwendung einer IP anstelle eines Hostnamens
verify-full prüft, dass das Zertifikat zum Hostnamen passt. Wenn deine URL eine IP wie 10.0.0.12 enthält, das Zertifikat aber für db.myprovider.com ausgestellt ist, schlägt die Verifikation fehl.
5) Umgebungsvariablen überschreiben, was du zu setzen glaubst
Es ist üblich, Code zu ändern, neu zu deployen und trotzdem Fehler zu bekommen, weil die Plattform DATABASE_URL (oder eine andere Variable) injiziert, die deine Änderungen überschreibt. Die App verwendet weiter die alte URL.
6) Copy-Paste des URLs und dadurch beschädigtes Passwort
Passwörter mit Sonderzeichen (@, :, #, %) müssen in URLs kodiert werden. Copy-Paste durch Dashboards, Chat-Tools oder .env-Dateien kann sie beschädigen und Auth-Fehler erzeugen, die wie SSL-Probleme aussehen.
Wenn du schnelle Checks machen willst, bevor du tiefer grabst:
- Bestätige, dass dein Treiber die von dir genutzte SSL-Einstellung liest (Name und Groß-/Kleinschreibung).
- Stimme
sslmodeauf die Anforderungen der Produktion ab, nicht auf das, was lokal toleriert wird. - Wenn du verifizierst, stelle sicher, dass das CA-Zertifikat zur Laufzeit vorhanden und zugreifbar ist.
- Verwende einen Hostnamen (keine IP) bei
verify-full. - Prüfe, ob keine Umgebungsvariable deine beabsichtigte Connection-String überschreibt.
Schritt für Schritt: Produktions-Verbindungseinstellungen korrekt aufbauen
Die Lösung beginnt damit, die finalen, effektiven Verbindungseinstellungen sichtbar und bewusst zu machen.
1) Liste aller Orte, von denen Konfiguration kommen kann
Bevor du etwas änderst, liste alle Quellen auf, die die Datenbankverbindung beeinflussen können: Laufzeit-Umgebungsvariablen, Plattform-Secrets, App-Konfigdateien, Build-time-Injection und ORM-Einstellungen.
Bestätige dann, welche Quelle gewinnt, wenn dieselbe Einstellung mehrfach vorkommt. Viele „SSL-Mode“-Bugs entstehen, weil man die falsche Stelle editiert hat.
2) Eine Single Source of Truth für den Connection-String erstellen
Wähle eine kanonische Darstellung für Produktion, normalerweise eine einzige DATABASE_URL. Entferne andere Stellschrauben (wie separate SSL-Flags) oder leite sie strikt aus dieser URL ab.
Eine gute Produktions-URL sagt die SSL-Absicht explizit:
postgres://USER:PASSWORD@HOST:5432/DBNAME?sslmode=verify-full
Wenn dein Provider Verschlüsselung verlangt, aber keine strikte Identitätsprüfung, kannst du sslmode=require nutzen. Wenn vollständige Verifikation gefordert ist, verwende verify-full und konfiguriere Zertifikate und Hostnamen entsprechend.
3) Lege den beabsichtigten SSL-Modus nach den Provider-Anforderungen fest
Rate nicht. Wähle den Modus basierend auf der Vorgabe des Providers und notiere kurz warum (ein Kommentar neben der Variable reicht). Das verhindert späteres Auseinanderdriften.
4) CA-Zertifikat und erwarteten Servernamen konfigurieren, wenn nötig
Für verify-ca und verify-full brauchst du in der Regel das CA-Zertifikat des Providers zur Laufzeit (als Dateipfad oder direkt übergeben, abhängig vom Treiber).
Für verify-full muss der Servername mit dem Zertifikat übereinstimmen. Wenn du per IP oder über einen Alias verbindest, kannst du trotz korrekter Credentials einen Mismatch bekommen.
5) Eine sichere, redigierte Ausgabe der finalen Konfiguration loggen
Logge, was die App nach allen Überschreibungen nutzt — niemals Passwörter, Tokens oder vollständige Zertifikatsinhalte.
DB host=prod-db.example.com port=5432 db=app sslmode=verify-full sslrootcert=set user=app_user password=REDACTED
Diese eine Zeile beim Start reicht oft, um einen falschen Host, einen fehlenden CA-Pfad oder einen unerwarteten SSL-Mode zu erkennen.
Schritt für Schritt: lokal denselben SSL-Modus testen
Ziel ist, dass dein Laptop sich wie Produktion verhält. Wenn Produktion SSL verlangt und deine lokale Umgebung stillschweigend ohne SSL verbindet, wirst du den Fehler erst nach dem Deployment sehen.
1) Produktive Eingaben nachbilden, nicht nur Werte
Starte lokal mit denselben Inputs wie Produktion: vollständige DB-URL, SSL-Modus und alle Zertifikatspfade. Vermeide es, „lokale Defaults“ mit Produktionswerten zu mischen.
Ein praktisches Muster ist eine dedizierte lokale Datei, z. B. .env.prodlike, und die App nur mit dieser Datei zu starten.
# Example (names vary by framework/driver)
DATABASE_URL=postgres://user:[email protected]:5432/appdb?sslmode=verify-full
PGSSLMODE=verify-full
PGSSLROOTCERT=./certs/prod-ca.pem
2) Dieselbe CA-Zertifikatskette mitbringen
Exportiere oder lade das in Produktion genutzte CA-Bündel herunter und speichere es lokal (z. B. ./certs/prod-ca.pem). Zeige deinen Treiber auf diese Datei. Ohne sie schlagen verify-ca und verify-full fehl, selbst wenn sonst alles stimmt.
3) Erzwinge den exakten SSL-Modus und verhindere „Auto-Fallback“
Einige Bibliotheken probieren mehrere Optionen oder fallen bei SSL-Fehlern auf unverschlüsselt zurück. Das verbirgt das eigentliche Problem. Mache den SSL-Mode explizit und achte auf Logs, die Retries mit anderen TLS-Einstellungen anzeigen. Wenn du „retrying without TLS/SSL“ siehst, behandle das als fehlgeschlagenen Test.
4) Sorge dafür, dass der Hostname dem entspricht, den verify-full prüft
Wenn du lokal per IP, localhost oder einem anderen DNS-Namen verbindest als in Produktion, kann verify-full scheitern, auch wenn die CA korrekt ist.
Verwende denselben DNS-Hostnamen wie in Produktion. Falls nötig, mappe ihn lokal via hosts-Datei/DNS, damit der Hostname gleich bleibt.
5) Kontrolle außerhalb deiner App
Bevor du deinen Code beschuldigst, teste die Verbindung mit einem einfachen Client und denselben Einstellungen. Scheitert dieser Test, liegt das Problem bei SSL-Konfiguration, Zertifikaten, DNS oder Netzwerk — nicht bei deiner App.
Den Fix beweisen: kurze Tests vor dem Redeploy
Nachdem du SSL-Einstellungen geändert hast, beweise, dass die Verbindung funktioniert, bevor du deployst. Isoliere das Problem vom App-Stack, damit du nicht rätst, ob die Änderung wirklich geholfen hat.
Ein kurzer Proof-Plan:
- Verbinde aus derselben Umgebung wie Produktion (gleiches Container-Image oder gleiche VM) mit einem minimalen Client.
- Gib die finalen, sanitisierten Connection-Einstellungen aus und bestätige, dass der SSL-Mode korrekt ist.
- Prüfe, ob die Laufzeit die konfigurierte CA-Datei lesen kann (Datei existiert, Berechtigungen passen).
- Vergleiche Treiberversionen zwischen lokal und Produktion (Defaults ändern sich über Versionen).
- Wenn du Container verwendest, prüfe, ob das Image System-CA-Bundles enthält (minimal-Images fehlen diese oft).
Wenn die Verbindung funktioniert, unterbreche sie absichtlich, um zu bestätigen, dass du verstehst, was validiert wird:
- Ändere den Hostnamen auf einen falschen und verifiziere, dass ein DNS/Connection-Fehler auftritt.
- Wechsle zu einem strengeren Modus (
verify-full) ohne passende CA und bestätige Zertifikatsfehler. - Setze den CA-Pfad auf eine fehlende Datei und überprüfe, dass ein Datei-/Permission-Fehler erscheint.
Wenn diese Änderungen den Fehler nicht beeinflussen, testest du wahrscheinlich nicht denselben Codepfad wie in Produktion. Das bedeutet oft, dass SSL-Einstellungen ignoriert oder überschrieben werden.
Beispiel-Szenario: ein verwalteter DB-Dienst verlangt SSL in Produktion
Ein verbreitetes Muster: lokal funktioniert alles, nach dem Deploy kann die App nicht verbinden. Die Logs zeigen „SSL handshake failed“, „certificate verify failed“ oder „server does not support SSL, but SSL was required“.
Meistens läuft lokal Postgres ohne SSL oder der Client toleriert schwächere Einstellungen. In Produktion verlangt der verwaltete Dienst SSL, und deine App läuft in einem Container ohne die richtigen CA-Zertifikate.
Die Ursache ist häufig eine Inkonsistenz zwischen drei Dingen: dem Hostnamen, zu dem du verbindest, dem gewählten SSL-Modus und der Frage, ob die Laufzeit die Zertifikatskette verifizieren kann.
Beispiel: Du deployst mit:
DATABASE_URL=postgres://app:[email protected]:5432/prod?sslmode=verify-full
Das kann fehlschlagen, obwohl die Credentials korrekt sind. verify-full verlangt, dass das Zertifikat vertrauenswürdig ist und zum Hostnamen passt. Eine IP-Adresse (oder ein Alias) passt in der Regel nicht zum DNS-Namen im Zertifikat.
Ein minimaler Fix ist, über den Hostnamen zu verbinden, für den das Zertifikat ausgestellt wurde, und sicherzustellen, dass die Laufzeit die Validierung durchführen kann:
DATABASE_URL=postgres://app:[email protected]:5432/prod?sslmode=verify-full\u0026sslrootcert=/etc/ssl/certs/ca-certificates.crt
Wenn du keinen CA-Bundle-Pfad angeben kannst (oder dein Image enthält ihn nicht), ist ein temporärer Workaround sslmode=require, sodass der Traffic verschlüsselt wird, aber ohne strikte Verifikation. Das kann dich zwar kurzfristig wieder online bringen, ist aber weniger sicher als vollständige Verifikation.
Um Wiederholungen zu vermeiden:
- Verwende lokal dieselbe Hostname-Form wie in Produktion (DNS-Name, nicht IP).
- Wähle den SSL-Mode bewusst und dokumentiere ihn.
- Stelle sicher, dass dein Runtime-Image CA-Zertifikate enthält und du weißt, wo das CA-Bundle liegt.
- Füge einen Smoke-Test hinzu, der im selben Container-Image läuft wie das Deployment.
Häufige Fallen in KI-generierten Apps (Lovable, Bolt, v0, Cursor, Replit)
Mit Tools wie Lovable, Bolt, v0, Cursor und Replit generierte Apps scheitern oft auf eine bestimmte Weise: Die DB-Einstellungen sehen plausibel aus, sind aber geraten. Deshalb treten SSL-Fehler erst nach dem Deployment auf.
Ein Muster ist ein erfundener Connection-String-Parameter, den dein Treiber nicht nutzt. Eine App könnte ssl=true oder tls=true setzen und denken, das erzwinge SSL, während der Treiber nur sslmode=require (oder ein strukturiertes ssl-Objekt) beachtet. Lokal akzeptiert die DB plain TCP, sodass du es nicht bemerkst. In Produktion verlangt der verwaltete Postgres SSL und die Verbindung schlägt fehl.
Ein weiteres Muster sind versteckte Überschreibungen. Diese Projekte setzen DB-Konfiguration an mehreren Stellen; du behebst nur eine Stelle. Lokal gewinnt dann die .env, in Produktion aber ein anderer Variablenname, eine injizierte Plattform-Variable oder ein Build-Default.
Die einfachste Refactor-Maßnahme, die Wiederholungen verhindert, ist unspektakulär, aber effektiv: Wähle eine Quelle der Wahrheit (meist DATABASE_URL), parse sie einmal und übergib dieselben Einstellungen an alle Stellen, die mit der DB arbeiten (Runtime, Migrations, Background-Jobs).
Kurze Checkliste und nächste Schritte
Wenn ein SSL-Fehler nur in Produktion auftritt, ist er selten zufällig. Meist ist es eine kleine Abweichung zwischen dem, was deine App anfordert, und dem, was die DB erwartet.
Checkliste:
- Bestätige, dass Host und Port mit dem verwalteten DB-Endpunkt übereinstimmen (kein alter Dev-Host, kein fehlender Port).
- Bestätige, dass der beabsichtigte SSL-Mode gesetzt ist (z. B.
requirevsverify-full) und dein Treiber ihn tatsächlich liest. - Wenn du Zertifikate verifizierst: stelle sicher, dass das CA-Zertifikat in der Laufzeit (VM, Container, Serverless) vorhanden ist und der Pfad korrekt ist.
- Prüfe, dass der Hostname im Connection-String mit dem Zertifikat-Hostname übereinstimmt (häufige
verify-full-Ursache). - Sorge für eine einzige Quelle der Wahrheit für die Konfiguration, nicht verstreute Overrides in Code und Dashboards.
Wenn du weiter „funktioniert auf meinem Rechner“ siehst, vergleiche Treiberversionen und Trust-Stores. Ein Container-Image könnte kein CA-Bundle enthalten oder Produktion läuft mit einer anderen Client-Bibliothek, die andere SSL-Defaults hat.
Ein leichter nächster Schritt ist ein Preflight beim Start, der schnell mit einer klaren Nachricht fehlschlägt:
Preflight idea: on startup, connect with the same connection string.
If it fails, log: sslmode, host, and whether a CA file was found.
Exit so the deploy fails early instead of timing out later.
Wenn du ein KI-generiertes Prototyp-Repo geerbt hast und die SSL-/Konfig-Logik über das Projekt verstreut ist, konzentriert sich FixMyMess (fixmymess.ai) auf Diagnose und Reparatur dieser produktionsspezifischen Ausfälle. Ein kurzer Audit identifiziert widersprüchliche Connection-Strings, fehlende CA-Handhabung und unsichere Defaults, damit die App in Produktion vorhersehbar funktioniert.
Häufige Fragen
Why do SSL errors show up only after I deploy to production?
Es bedeutet meistens, dass Produktion über einen verwalteten Datenbank-Endpunkt verbunden ist, der SSL zwingend vorschreibt und eventuell Zertifikatsprüfungen durchführt, während deine lokale Datenbank plain TCP erlaubt oder stillschweigend auf nicht-verschlüsselt zurückfällt. Der Code kann gleich sein, aber Umgebungs-Defaults und Netzweg unterscheiden sich.
What’s the difference between sslmode=require and sslmode=verify-full?
require verschlüsselt die Verbindung, prüft aber nicht strikt die Identität des Servers. verify-full verschlüsselt ebenfalls, prüft aber zusätzlich die Zertifikatskette und ob der Hostname, zu dem du verbindest, mit dem Zertifikat übereinstimmt — das schlägt oft fehl, wenn du eine IP, einen Proxy-Hostname oder einen falschen DNS-Namen verwendest.
Why does it fail with “hostname mismatch” when I use an IP address?
Weil verify-full eine exakte Hostnamen-Übereinstimmung erwartet, und Zertifikate selten auf rohe IP-Adressen ausgestellt werden. Verwende den DNS-Hostnamen deines Providers, für den das Zertifikat ausgestellt wurde, nicht eine private IP oder einen internen Alias, wenn strenge Verifikation nötig ist.
What does “unable to get local issuer certificate” mean in production?
Das bedeutet in der Regel, dass die Laufzeitumgebung die Zertifikatskette nicht verifizieren kann. Häufige Ursachen sind fehlende CA-Zertifikate im Container/VM, ein falscher sslrootcert-Pfad oder ein minimales Basis-Image ohne System-CA-Bundles.
What should I log to diagnose this without leaking secrets?
Gib beim Start den aufgelösten Datenbank-Host, Port, Datenbanknamen und die SSL-Mode-Einstellung aus, dabei die Zugangsdaten unkenntlich machen. Erfasse außerdem den ersten Fehler und alle „caused by“-Zeilen, da Retries die eigentliche Fehlerursache verschleiern können.
Why does it still fail after I “set SSL” in my config?
Oft ignoriert der Treiber deine SSL-Einstellungen wegen falscher Optionennamen oder Groß-/Kleinschreibung, oder eine Umgebungsvariable wie DATABASE_URL überschreibt die Änderungen. Eine weitere häufige Ursache ist ein Proxy/Pooler in Produktion, der ein anderes Zertifikat präsentiert als erwartet.
How can I make my local environment behave like production for SSL?
Starte lokal mit genau dem produktionsähnlichen Connection-String und SSL-Mode, inklusive derselben CA-Zertifikat-Eingaben. Ziel ist es, zu verhindern, dass prefer oder andere Fallback-Verhalten Probleme verbergen, bis du deployst.
Could this be caused by my DATABASE_URL or a copy-paste mistake?
Zuerst bestätige, welche DATABASE_URL die App zur Laufzeit tatsächlich verwendet, denn Plattformen setzen oder überschreiben diese oft. Verifiziere dann, dass der Treiber den Parameter liest, den du setzt, und dass Sonderzeichen im Passwort URL-kodiert sind — fehlerhafte URLs können wie SSL-Fehler aussehen.
Can PgBouncer or a proxy cause intermittent SSL failures?
Ja. Wenn Produktion über PgBouncer, einen Load Balancer oder einen privaten Endpunkt läuft, kann der präsentierte Hostname und das Zertifikat vom getesteten abweichen. Das kann zu intermittierenden Handshake-Fehlern oder Verifikationsfehlern führen, besonders wenn der Pooler Endpunkte rotiert oder eine andere Zertifikatskette verwendet.
When should I ask FixMyMess to step in?
Wenn das Projekt KI-generiert ist oder die Konfiguration über viele Stellen verstreut ist, ist ein fokussiertes Audit die schnellste Lösung, um die effektiven Connection-Einstellungen und die Inkonsistenzen zu finden. FixMyMess kann eine kostenlose Code-Analyse durchführen und dann die Verbindungslogik, SSL-Handhabung und unsichere Defaults reparieren — die meisten Fixes in 48–72 Stunden, mit Option auf sauberen Rebuild in ~24 Stunden, wenn das Repo nicht mehr patchbar ist.