Ошибка "SSL is not enabled on the server" при подключении к PostgreSQL из Go
Понимание проблемы: почему возникает ошибка
Ваша ошибка — классический случай, когда сервер PostgreSQL настроен на обязательное SSL-соединение, а клиент пытается подключиться без шифрования (sslmode=disable). Сервер отклоняет такое подключение. При попытке включить SSL без правильных сертификатов (sslmode=require) возникает вторая ошибка, потому что Go не может проверить сертификат сервера.
Решение: правильная настройка SSL-соединения
Вам нужно настроить три вещи:
- Правильный режим SSL (
sslmode) - Путь к корневому сертификату CA (если используете
verify-full) - Проверить, что сервер PostgreSQL поддерживает TLS (версии 1.2 или 1.3)
Шаг 1. Определите режим SSL
Для большинства облачных баз данных (AWS RDS, DigitalOcean, Heroku) достаточно использовать sslmode=require. Этот режим шифрует соединение, но не проверяет сертификат сервера. Если вам нужна максимальная безопасность — используйте sslmode=verify-full, но тогда потребуется CA-сертификат.
Шаг 2. Получите сертификат CA
Для verify-full скачайте корневой сертификат вашего провайдера. Например, для AWS RDS:
wget https://s3.amazonaws.com/rds-downloads/rds-ca-2019-root.pem -O ~/certs/rds-ca.pem
Шаг 3. Исправьте код
Вот рабочий пример для sslmode=require (без проверки сертификата):
package main
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
)
func main() {
// sslmode=require — шифрование без проверки сертификата
connStr := "host=mycloudserver.com port=5432 user=myuser password=mypass dbname=mydb sslmode=require"
db, err := sql.Open("postgres", connStr)
if err != nil {
panic(err)
}
defer db.Close()
err = db.Ping()
if err != nil {
fmt.Println("Ошибка:", err)
} else {
fmt.Println("Подключение успешно!")
}
}
Если хотите проверять сертификат (рекомендуется для продакшена):
// sslmode=verify-full требует CA-сертификат
connStr := "host=mycloudserver.com port=5432 user=myuser password=mypass dbname=mydb sslmode=verify-full sslrootcert=/home/user/certs/rds-ca.pem"
Шаг 4. Альтернатива: настройка через SSL-конфигурацию Go
Если у вас нестандартные требования (например, самоподписанный сертификат), используйте программную настройку TLS:
import (
"crypto/tls"
"crypto/x509"
"database/sql"
"fmt"
"io/ioutil"
"log"
_ "github.com/lib/pq"
)
func main() {
// Загружаем CA-сертификат
caCert, err := ioutil.ReadFile("/home/user/certs/ca.pem")
if err != nil {
log.Fatal(err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
// Настраиваем TLS
tlsConfig := &tls.Config{
RootCAs: caCertPool,
// Для самоподписанных сертификатов: InsecureSkipVerify: true (не для продакшена!)
}
// Строка подключения без sslmode
connStr := "host=mycloudserver.com port=5432 user=myuser password=mypass dbname=mydb"
db, err := sql.Open("postgres", connStr)
if err != nil {
log.Fatal(err)
}
// Устанавливаем TLS-конфигурацию через драйвер
// (lib/pq поддерживает это через параметр sslmode=require + настройку)
// Альтернатива: используйте pgx — он лучше работает с кастомным TLS
fmt.Println("Подключение через lib/pq с кастомным TLS настроено")
_ = db
}
Важные советы
- Проверьте версию Go — старая версия может не поддерживать современные TLS-протоколы.
- Используйте pgx — более современный драйвер, который проще настраивать под SSL:
go get github.com/jackc/pgx/v5. - Не используйте
sslmode=disableв продакшене — это угроза безопасности. - Если сервер использует самоподписанный сертификат, добавьте его в доверенные или используйте
sslmode=require.
Альтернативный подход: использование драйвера pgx
Драйвер lib/pq хорош, но у него ограниченная поддержка кастомных TLS-настроек. Рекомендую перейти на pgx — он официально поддерживается, быстрее и гибче в настройке SSL.
Пример с pgx
package main
import (
"context"
"fmt"
"github.com/jackc/pgx/v5/pgxpool"
)
func main() {
// Строка подключения с SSL-настройками
connStr := "postgres://myuser:mypass@mycloudserver.com:5432/mydb?sslmode=require"
pool, err := pgxpool.New(context.Background(), connStr)
if err != nil {
panic(err)
}
defer pool.Close()
var greeting string
err = pool.QueryRow(context.Background(), "select 'Hello, world!'").Scan(&greeting)
if err != nil {
fmt.Println("Ошибка:", err)
} else {
fmt.Println(greeting)
}
}
Преимущества pgx
- Поддерживает все режимы SSL:
disable,require,verify-ca,verify-full. - Позволяет передавать TLS-конфигурацию через
pgxpool.Config. - Лучшая производительность и поддержка Go-контекстов.
- Меньше проблем с сертификатами — pgx автоматически ищет системные CA.
Если pgx не подходит
Попробуйте установить переменную окружения PGSSLMODE=require перед запуском программы — это сработает для lib/pq без изменения кода:
export PGSSLMODE=require
go run main.go
Но помните: это временное решение. Для продакшена всегда настраивайте SSL явно.