Encrypt in the application if you need protection from people who administer the database. pgcrypto functions run inside the database server, so the data and passwords move between pgcrypto and client applications in clear text. It helps against a stolen disk or backup, not against a trusted insider or a compromised server.
What the PostgreSQL docs say
The pgcrypto documentation has a section titled security limitations. It states that all pgcrypto functions run inside the database server, which means all the data and passwords move between pgcrypto and client applications in clear text. As a result you must connect locally or use SSL connections, and trust both the system and the database administrator. It adds that if you cannot, it is better to do the cryptography inside the client application.
The same section says the implementation does not resist side channel attacks. For example, the time a decryption function takes varies among ciphertexts of a given size.
Two places to encrypt
| Question | In the database with pgcrypto | In the application |
|---|---|---|
| Where does the key sit when used? | In the query, so the server sees it | In the app process only |
| Can a DBA read plaintext? | Possibly, since the server sees data and keys | No, if the key never reaches the database |
| Can SQL search the column? | Only after decryption, which is costly | Not directly, design for lookup separately |
| Protects a stolen backup? | Yes, for encrypted columns | Yes |
| Protects against a compromised database host? | Weakly | Better |
| Complexity | Lower | Higher, you manage keys in code |
The practical pattern is to decide whose compromise you are defending against. A stolen backup or disk is covered by both. A rogue administrator or a read only attacker on the database server is only covered if the key stays out of the database.
A hidden risk in the docs
The documentation also says that, as is standard in SQL, all functions return NULL if any of the arguments are NULL, and that this may create security risks on careless usage. A missing key or a failed lookup can turn into a NULL that your code treats as empty rather than as an error. Check for NULL explicitly after any encrypt or decrypt call.
If you encrypt in the application
- Use an established library and a standard authenticated mode rather than writing your own.
- Keep data keys wrapped by a key held in a key management service. See envelope encryption explained.
- Store the ciphertext in a binary or text column and keep a key identifier next to it, so you can rotate.
- Plan search up front. Encrypted columns cannot be matched with a simple equality or LIKE unless you add a separate design for it.
- Never log plaintext or keys. See what never to log.
If you use pgcrypto anyway
- Connect over TLS and verify the certificate. See sslmode verify-full.
- Be careful that statements containing keys do not land in server logs. See PostgreSQL log settings that avoid leaking secrets.
- Restrict who can read the database logs and run queries as a superuser.
- Do not use pgcrypto to store login passwords. Our post on Argon2id password storage explains current guidance.
For the broader decision of disk, database or application level encryption, see encryption at rest at disk, database or application level.
Safeguard scans dependencies, including crypto and database libraries, and can find exposed secrets in repositories. A free scan is at gold.safeguard.sh/scan.
Quick check
Does pgcrypto protect me from a database administrator?
No. The docs say you must trust the system and database administrator, or do the cryptography in the client application.
Does pgcrypto resist timing attacks?
The docs say it does not resist side channel attacks.
What happens if an argument is NULL?
The functions return NULL, which the docs say may create security risks on careless usage.
Sources
Last reviewed: 19 October 2026.