Use PostgreSQL features and SQL techniques to encrypt, anonymize, monitor, and delete personal data for GDPR compliance.
GDPR requires you to protect personal data, limit retention, allow user deletion requests, and keep audit trails. PostgreSQL can satisfy these rules with built-in encryption, row-level security, and logging.
Enable pgcrypto or Postgres 16’s built-in encryption. Store only ciphertext in columns such as Customers.email. Keep keys in a Hardware Security Module (HSM) or environment variable outside the database.
UPDATE Customers
SET email = pgp_sym_encrypt(email, :key)
WHERE id = 42;
Create a view that masks or hashes fields once they exceed the legal retention window. Use generated columns or views so analytic queries still work without exposing raw data.
CREATE VIEW v_orders_gdpr AS
SELECT id,
customer_id,
CASE WHEN order_date < CURRENT_DATE - INTERVAL '3 years'
THEN '*** anonymized ***'
ELSE total_amount::text END AS total_amount
FROM Orders;
Wrap DELETEs in a function that cascades through related tables, then VACUUM to purge pages. Maintain a deletion log for accountability.
BEGIN;
DELETE FROM OrderItems WHERE order_id IN (
SELECT id FROM Orders WHERE customer_id = :cust_id);
DELETE FROM Orders WHERE customer_id = :cust_id;
DELETE FROM Customers WHERE id = :cust_id;
COMMIT;
VACUUM FULL;
Turn on log_statement = "mod"
and send logs to an immutable store like S3. Use the pg_audit
extension for column-level auditing in tables that hold personal data.
Schedule cron jobs or CI pipelines that run SQL to find unencrypted columns, stale records, or missing indices. Alert when issues appear.
pg_audit adds column-level read/write logs, meeting GDPR’s accountability mandate. While basic logging works, pg_audit makes evidence collection easier.
Yes. VACUUM FULL rewrites tables, eliminating dead tuples that could otherwise be recovered from disk.
Create a staging copy of production, run anonymization scripts, and diff outputs. Automated tests ensure masking remains effective after schema changes.