Preamble
Maintaining PostgreSQL’s security is something we want to do. Therefore, considering the use of SSL to protect client-server communication only makes sense. This article will help you set up PostgreSQL’s SSL authentication correctly and, hopefully, help you understand some background information to make your database more secure.
After reading this post, you ought to be able to easily configure PostgreSQL and handle secure client-server connections.
Configuring PostgreSQL for OpenSSL
We must modify Postgresql.conf before configuring OpenSSL. Several factors are linked to encryption, including:
ssl = on #ssl_ca_file = '' #ssl_cert_file = 'server.crt' #ssl_crl_file = '' #ssl_key_file = 'server.key' #ssl_ciphers = 'HIGH:MEDIUM:+3DES:!'aNULL' # allowed SSL ciphers'ssl_prefer_server_ciphers = on'ssl_ecdh_curve = 'prime256v1''ssl_min_protocol_version' = 'TLSv1.2''ssl_max_protocol_version' = '''ssl_dh_params_file' = '''s
Once ssl = on, the server will negotiate SSL connections in case they are possible. The remaining settings control things like where key files are located and how strong ciphers are. Please be aware that turning on SSL does not necessitate restarting the database. A straightforward reload will set the variable. However, PostgreSQL needs to be restarted otherwise it will reject SSL connections. The following is a significant problem that some users encounter quite frequently:
postgres=# SELECT pg_reload_conf(); pg_reload_conf ---------------- t (1 row) postgres=# SHOW ssl; ssl ----- on (1 row)
The SHOW command is an easy way to make sure that the setting has indeed been changed. Technically speaking, pg_reload_conf() is not required right now. In any case, you must start over later. We simply reloaded to show the effect on the variable.
The next step is to alter pg_hba.conf so that PostgreSQL will handle our connections securely:
# TYPE DATABASE USER ADDRESS METHOD # "local" is for Unix domain socket connections only local all all peer host all all 127.0.0.1/32 scram-sha-256 host all all ::1/128 scram-sha-256 hostssl all all 10.0.3.0/24 scram-sha-256
Restart the database instance after SSL has been enabled.
The next action is to create certificates. To keep things simple in this case, we’ll just create self-signed certificates. Of course, other certificates are also acceptable. The steps are as follows:
[postgres@node1 data]$ openssl req -new -x509 -days 365 \ -nodes -text -out server.crt \ -keyout server.key \ -subj "/CN=cybertec-postgresql.com" Generating a RSA private key .......+++++ ....................................................+++++ writing new private key to 'server.key' -----
This certificate has a 365-day expiration date. After that, the certificate must be made active by adjusting permissions. If those permissions are too lenient, the server won’t accept the certificate:
[postgres@node1 data]$ chmod og-rwx server.key
It’s nice to have certificates that you self-sign. You must first create a certificate signing request and a public/private key file in order to create a server certificate whose identity and origin can be verified by clients:
[postgres@node1 data]$ openssl req -new -nodes -text \ -out root.csr \ -keyout root.key \ -subj "/CN=cybertec-postgresql.com" Generating a RSA private key .................................+++++ ....................+++++ writing new private key to 'root.key' -----
We must confirm these permissions are exactly as they should be once more:
[postgres@node1 data]$ chmod og-rwx root.key
Then the request is signed. To use OpenSSL for that action, we must first find openssl.cnf. It’s not always in the same place, as we’ve seen, so make sure you’re taking the right path:
[postgres@node1 data]$ find / -name openssl.cnf \ 2> /dev/null /etc/pki/tls/openssl.cnf
We carry out the following steps after signing the request:
[postgres@node1 data]$ openssl x509 -req -in root.csr \ -text \ -days 3650 \ -extfile /etc/pki/tls/openssl.cnf \ -extensions v3_ca \ -signkey root.key -out root.crt Signature ok subject=CN = cybertec-postgresql.com Getting Private key
Let’s create a new certificate for the root authority:
[postgres@node1 data]$ openssl req -new -nodes -text \ -out server.csr \ -keyout server.key \ -subj "/CN=cybertec-postgresql.com" Generating a RSA private key .....................+++++ ...........................+++++ writing new private key to 'server.key' [postgres@node1 data]$ chmod og-rwx server.key [postgres@node1 data]$ openssl x509 -req \ -in server.csr -text -days 365 \ -CA root.crt -CAkey root.key -CAcreateserial \ -out server.crt Signature ok subject=CN = cybertec-postgresql.com Getting CA Private Key
server.crt and server.key should be stored on the server in your data directory as configured on postgresql.conf.
But there is more: root.crt should be stored on the client so the client can verify that the server’s certificate was signed by the certification authority. root.key should be kept offline so that it can be used when making new certificates.
The following files are needed:
|
File name
|
Purpose of the file
|
Remarks
|
|
ssl_cert_file ($PGDATA/server.crt)
|
certificate for a server
|
sent to the client to identify the server
|
|
ssl_key_file ($PGDATA/server.key)
|
individual server key
|
proves the owner of the server certificate sent it; does not imply the owner is reliable
|
|
ssl_ca_file
|
dependable certificate authorities
|
determines whether the client certificate was signed by a reliable certificate authority.
|
|
ssl_crl_file
|
Revocation of certificates by certificate authorities
|
Client certificates cannot be included in this list.
|
Checking your setup
The servers should now be restarted after installing all the certificates:
Systemctl restart postgresql-13 [root@node1]
The connection would break down and display an error message without a restart.(“psql: error: FATAL: no pg_hba.conf entry for host "10.0.3.200", user "postgres", database "test", SSL off”).
However, after the restart, the process should work as expected:
[root@node1 ~]# su - postgres [postgres@node1 ~]$ psql test -h 10.0.3.200 Password for user postgres: psql (13.2) SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off) Type "help" for help. test=#
Psql claims that the connection is encrypted; to verify this, we must look at the information in pg_stat_ssl:
postgres=# \d pg_stat_ssl View "pg_catalog.pg_stat_ssl" Column | Type | Collation | Nullable | Default ----------------+---------+-----------+----------+--------- pid | integer | | | ssl | boolean | | | version | text | | | cipher | text | | | bits | integer | | | compression | boolean | | | client_dn | text | | | client_serial | numeric | | | issuer_dn | text | | |
Let’s query the system view to examine its contents:
test=# \x Expanded display is on. test=# SELECT * FROM pg_stat_ssl; -[ RECORD 1 ]-+----------------------- pid | 16378 ssl | t version | TLSv1.3 cipher | TLS_AES_256_GCM_SHA384 bits | 256 compression | f client_dn | client_serial | issuer_dn |
The connection has been successfully encrypted if “ssl = true.”
Different levels of SSL supported by PostgreSQL
Two SSL configurations are not always the same. You can pick the level of security and protection you want from a number of options. The SSL modes that PostgreSQL supports are listed in the following table:
|
sslmode |
Eavesdropping protection |
MITM (= man in the middle) protection |
Statement |
|
disable
|
No
|
No
|
There is zero overhead if SSL and encryption are not used.
|
|
allow
|
Maybe
|
No
|
The client tries a connection that isn’t encrypted but switches to an encrypted one if the server asks for it.
|
|
prefer
|
Maybe
|
No
|
In the “deny” mode, the client tries to set up a secure connection, but if the server insists, it switches to an open one.
|
|
require
|
Yes
|
No
|
Data encryption is cost-effective and ought to be carried out. My desired server will be pointed out by the reliable network.
|
|
verify-ca
|
Yes
|
Depends on CA policy
|
Data encryption is necessary. Systems must ensure that the right server is connected to twice.
|
|
verify-full
|
Yes
|
Yes
|
strongest defense that is possible. Complete encryption and verification of the chosen target server.
|
The overhead is heavily influenced by the mode you are using.
The main issue at hand right now is how to specify the mode that will be used. The answer is that it needs to be hidden as part of the connect string, as shown in the next example:
[postgres@node1 data]$ psql "dbname=test host=10.0.3.200 user=postgres password=1234 sslmode=verify-ca" psql: error: root certificate file "/var/lib/pgsql/.postgresql/root.crt" does not exist Either provide the file or change sslmode to disable server certificate verification.
Verify-ca doesn’t work in this case because the root.* files need to be copied to the client and the certificates need to be able to validate the target server.
Encrypting your entire server: PostgreSQL TDE
The link between the client and the server has been encrypted so far. However, there are times when it’s imperative to completely encrypt the server, including the storage.
What might also interest you …
Materialized views are a vital part of the majority of databases, including PostgreSQL. They can, at the very least, be used to cache large calculations.
About Enteros
Enteros offers a patented database performance management SaaS platform. It finds the root causes of complex database scalability and performance problems that affect business across a growing number of cloud, RDBMS, NoSQL, and machine learning database platforms.
The views expressed on this blog are those of the author and do not necessarily reflect the opinions of Enteros Inc. This blog may contain links to the content of third-party sites. By providing such links, Enteros Inc. does not adopt, guarantee, approve, or endorse the information, views, or products available on such sites.
Are you interested in writing for Enteros’ Blog? Please send us a pitch!
RELATED POSTS
Driving Enterprise Efficiency Through AI-Based Database Performance Optimization
- 12 June 2026
- Database Performance Management
Introduction In today’s digital-first economy, enterprises depend heavily on data-driven applications to power everything from customer transactions to real-time analytics and AI workloads. As these systems scale, database performance becomes a critical determinant of business success. Even minor inefficiencies—slow queries, resource contention, or poor scaling strategies—can lead to significant revenue loss, degraded user experience, and … Continue reading “Driving Enterprise Efficiency Through AI-Based Database Performance Optimization”
How Predictive Database Monitoring Improves Application Uptime and Business Continuity
In today’s always-on digital economy, application availability is no longer just an IT metric—it is a business imperative. Customers expect seamless digital experiences, employees depend on uninterrupted access to critical systems, and organizations rely on applications to drive revenue, operations, and customer engagement. Whether supporting e-commerce transactions, financial services, healthcare applications, SaaS platforms, or telecommunications … Continue reading “How Predictive Database Monitoring Improves Application Uptime and Business Continuity”
Preventing Database Bottlenecks with Intelligent Workload Analytics and Automation
- 11 June 2026
- Database Performance Management
In today’s digital economy, application performance directly impacts customer satisfaction, operational efficiency, and business growth. Organizations rely on databases to power customer-facing applications, financial transactions, e-commerce platforms, analytics systems, SaaS solutions, and countless other mission-critical services. As enterprises continue to embrace cloud-native architectures, microservices, multi-cloud deployments, and real-time data processing, database workloads have become increasingly … Continue reading “Preventing Database Bottlenecks with Intelligent Workload Analytics and Automation”
The Future of AI-Powered Database Performance Management in Enterprise IT Operations
Enterprise IT operations are undergoing a significant transformation. As organizations accelerate digital transformation initiatives, adopt cloud-native architectures, expand multi-cloud deployments, and implement AI-driven business strategies, the complexity of managing database environments continues to grow. Databases have evolved from simple data repositories into mission-critical components that power applications, analytics platforms, customer experiences, and business operations. Modern … Continue reading “The Future of AI-Powered Database Performance Management in Enterprise IT Operations”