
August 15, 2026
12 min read
By Kokil Thapa | Last reviewed: September 2026
Your database holds the data attackers want most: customer records, payment references, and legal documents. Encryption in transit and at rest closes two separate gaps—plaintext on stolen disks and plaintext on the wire between your app and the database server. On a recent audit of a Laravel production app in Nepal, TLS was enabled but certificate verification was off, so a man-in-the-middle on the same VPC could still read queries. This guide walks through both layers for MySQL 9.7, PostgreSQL 18, and Laravel 13 on PHP 8.3 or higher.
require-secure-transport on MySQL, hostssl in PostgreSQL, and LUKS or cloud TDE for at-rest protection. Add column-level encryption only for the most sensitive fields.What Is the Difference Between Encryption at Rest and In Transit?
These two controls answer different threat models. Mixing them up is a common audit failure. Teams often enable HTTPS on the web tier and assume the database is covered. It is not.
Encryption at rest protects data stored on disk, SSD, or backup media. If someone steals a server from a Kathmandu colocation rack or downloads an unencrypted EBS snapshot, the raw bytes stay unreadable without the decryption key. Methods include cloud-managed TDE, filesystem encryption with LUKS or ZFS, and application-layer column encryption.
Encryption in transit protects data moving between your Laravel app and the database. Without TLS, any host on the network path can read SQL queries and result sets. This includes shared switches, compromised containers in the same cluster, and misconfigured VPC peering.
For teams running secure web infrastructure in Nepal, shared hosting and physical access risks make both layers essential. The Electronic Transactions Act 2063 (2008) and the Privacy Act 2075 (2018) expect reasonable safeguards for personal data. Encryption alone does not satisfy every legal requirement, but it is a baseline control auditors ask about first.
How Do You Enforce TLS for MySQL and PostgreSQL Connections?
In-transit encryption must be mandatory, not opportunistic. Many PHP drivers attempt TLS but fall back to plaintext when negotiation fails. That silent downgrade defeats the entire control.
MySQL 9.7 with require-secure-transport
MySQL generates self-signed certificates at install time. Production systems should use certificates from an internal CA or Let's Encrypt. Edit my.cnf on the database server:
[mysqld]
ssl-ca=/etc/mysql/certs/ca.pem
ssl-cert=/etc/mysql/certs/server-cert.pem
ssl-key=/etc/mysql/certs/server-key.pem
require-secure-transport=ON
tls-version=TLSv1.3 The require-secure-transport=ON directive rejects any non-TLS connection. On the Laravel 13 side, your .env must verify the certificate chain:
DB_CONNECTION=mysql
DB_HOST=db.example.com
DB_PORT=3306
DB_DATABASE=legal_portal
DB_USERNAME=app_user
DB_PASSWORD="${DB_PASS}"
MYSQL_ATTR_SSL_CA=/etc/app/certs/ca.pem
MYSQL_ATTR_SSL_VERIFY_SERVER_CERT=true Setting MYSQL_ATTR_SSL_CA without VERIFY_SERVER_CERT is a mistake I see often. Your app accepts any certificate signed by that CA, including one from an active attacker. Always verify. The official MySQL encrypted connections documentation covers the full attribute list.
PostgreSQL 18 with hostssl and verify-full
PostgreSQL controls transport security through pg_hba.conf. Change relevant entries from host to hostssl:
# TYPE DATABASE USER ADDRESS METHOD
hostssl legal_db app_user 10.0.0.0/24 scram-sha-256
hostssl legal_db app_user ::/0 scram-sha-256 In postgresql.conf, enable TLS and set the minimum protocol:
ssl = on
ssl_cert_file = '/etc/postgresql/18/main/server.crt'
ssl_key_file = '/etc/postgresql/18/main/server.key'
ssl_ca_file = '/etc/postgresql/18/main/root.crt'
ssl_min_protocol_version = 'TLSv1.3' Laravel's PDO driver respects the sslmode parameter. Use verify-full in production:
DB_CONNECTION=pgsql
DB_HOST=db.example.com
DB_PORT=5432
DB_DATABASE=legal_db
DB_OPTIONS="sslmode=verify-full;sslrootcert=/etc/app/certs/root.crt" The weaker require mode only confirms TLS was negotiated. It does not validate the hostname. See the PostgreSQL SSL documentation for the full mode comparison. For deeper PostgreSQL setup, read our PostgreSQL for Laravel developers guide.
Which Encryption-at-Rest Strategy Fits Your Infrastructure?
The right at-rest approach depends on who manages your hardware and what compliance regime applies. There is no universal best option—only trade-offs that match your budget and team size.
| Method | Best For | Key Management | Performance Impact | Typical Cost (Nepal VPS) |
|---|---|---|---|---|
| Cloud TDE (RDS/Azure) | Managed databases | Provider KMS | Negligible | Rs 8,000–25,000/mo (~USD 60–185) |
| Filesystem (LUKS/ZFS) | Self-hosted VPS | OS-level keys | 5–10% | Rs 3,000–8,000/mo (~USD 22–60) |
| Database-native TDE | Enterprise compliance | External HSM/KMS | 10–20% | Rs 50,000+/mo (~USD 370+) |
| Application-layer | Specific PII fields | App secrets manager | Per-query overhead | Dev time only |
For most Laravel projects I deploy on Ubuntu 24.04 VPS instances, LUKS filesystem encryption provides the best balance. It needs no application changes. It works with any database engine. It protects backups automatically when they sit on the same encrypted volume. Cloud TDE is superior when available because key rotation and audit logging are handled by the provider.
Financial apps processing data under Nepal Rastra Bank payment-system guidelines should treat at-rest encryption as mandatory for production databases. The exact technical standard varies by license type, but unencrypted production disks fail every serious review.
When Should You Add Application-Layer Column Encryption?
Infrastructure encryption stops external attackers. It does not stop insiders with legitimate database access. A DBA with root credentials can still read plaintext rows. Application-layer encryption enforces separation of duties.
For legal-tech portals handling citizenship numbers, marriage certificates, or court documents, column encryption is often required. Laravel 13 supports native encrypted casting through Eloquent:
class Client extends Model
{
protected $casts = [
'citizenship_number' => 'encrypted',
'court_case_details' => 'encrypted',
];
} This uses AES-256-CBC with APP_KEY by default. Tying encryption to APP_KEY creates a single point of failure. Rotating the app key breaks all existing encrypted data. For production systems, use a dedicated encryption service with per-field keys stored in HashiCorp Vault or AWS Secrets Manager:
class Client extends Model
{
public function getCitizenshipNumberAttribute($value): ?string
{
return $value
? FieldEncryptionService::decrypt('citizenship', $value)
: null;
}
public function setCitizenshipNumberAttribute(?string $value): void
{
$this->attributes['citizenship_number'] = $value
? FieldEncryptionService::encrypt('citizenship', $value)
: null;
}
} Encrypted columns cannot be indexed or searched efficiently. If you need to query by citizenship number, store a blinded HMAC-SHA256 hash alongside the ciphertext. Query the hash, then decrypt the match. This pattern appears frequently in Nepal legal-tech implementations where searchability and confidentiality must coexist.
On the Mijar Law Associates client portal, document metadata stays searchable while file contents remain encrypted at the storage layer. The combination of at-rest disk encryption, TLS in transit, and column-level protection for national ID fields covers the full threat model.
How Do You Manage Encryption Keys and Rotate Them Safely?
Encryption is only as strong as key management. Losing keys means permanent data loss. Leaking keys means total compromise. Treat key lifecycle as a first-class engineering task, not an afterthought.
- Never store keys in Git or plain .env files. Inject them at runtime from a secrets manager. On Deployer 7 pipelines I maintain, secrets are pulled from GitLab CI variables during deployment.
- Separate DEKs from KEKs. Data encryption keys encrypt records. Key encryption keys wrap DEKs. Rotating a KEK re-wraps DEKs without re-encrypting terabytes of data.
- Automate rotation on a schedule. Manual rotation fails under pressure. Schedule quarterly KEK rotation via cron or CI. Test backup restoration after every cycle.
- Audit every decrypt operation. Log access patterns. Alert on bulk decryption outside business hours or from unexpected IP ranges.
- Document recovery before you need it. When a server dies at 2 AM, nobody remembers where the KEK backup lives. Maintain runbooks and test them quarterly.
Use our password generator tool for initial key material, but store production keys only in a dedicated secrets manager. See our guides on HashiCorp Vault secrets management and AWS KMS envelope encryption for production patterns.
What Compliance Rules Apply to Database Encryption in Nepal?
Technical encryption and legal compliance overlap but are not identical. Understanding both prevents you from shipping the wrong architecture to a regulated client.
The Privacy Act 2075 (2018) requires data controllers to protect personal information with appropriate security measures. Encryption is the most cited technical control in privacy impact assessments. The Act does not mandate a specific cipher or key length, but AES-256 with TLS 1.3 meets every reasonable interpretation.
For payment integrations using eSewa, Khalti, or ConnectIPS, follow each gateway's security requirements alongside NRB guidelines. Cardholder data falls under PCI DSS if you store PANs—most Nepali Laravel shops avoid this by tokenizing through the gateway. Read our PCI DSS essentials for developers if you touch card data at all.
The broader legal framework is covered in our data privacy law guide for Nepali web apps. Document your encryption choices in a data processing record. Auditors ask for this during due diligence for SaaS acquisitions and government tenders.
Server hardening complements database encryption. Follow our Ubuntu server security best practices and ensure backups are encrypted too. An unencrypted mysqldump on a plain ext4 partition negates every at-rest control on the live database.
How Do You Verify Encryption In Transit and At Rest Actually Works?
Configuration alone is insufficient. You must prove encryption is active and cannot be silently downgraded. Run these checks in CI and after every deployment.
- TLS verification: Connect with
mysql --ssl-mode=VERIFY_IDENTITYorpsql "sslmode=verify-full". Connection must succeed. Retry with--ssl-mode=DISABLED; it must fail. - Certificate expiry monitoring: Alert 30 days before certificate expiration. Expired certs cause hard outages or silent fallback on poorly configured clients.
- At-rest verification: For LUKS, run
lsblk -o NAME,FSTYPE,TYPEand confirmcrypto_LUKS. For cloud TDE, check the provider console encryption flag. - Column encryption test: Insert known plaintext via the app. Query directly through the MySQL CLI. Confirm ciphertext is returned, not the original value.
- Backup encryption: Restore to an isolated environment. Confirm encryption persists on the restored volume. See our database backup strategies guide and automated backup setup.
I add these checks to every GitLab CI pipeline for legal-tech and e-commerce clients. A passing test suite that skips encryption validation gives false confidence. Make verification automatic and blocking. Our OWASP Top 10 for Laravel guide covers related application-layer controls.
For enterprise deployments needing a full security review, our enterprise application development service includes encryption architecture as part of the initial design phase—not as a post-launch patch.
Key Takeaways
- Encryption in transit and at rest are separate controls—TLS protects the wire, LUKS or TDE protects the disk.
- Enforce
require-secure-transport=ONon MySQL andhostsslwithverify-fullon PostgreSQL; never allow plaintext fallback. - Use application-layer column encryption only for high-sensitivity fields like national IDs, not entire tables.
- Separate DEKs from KEKs so key rotation does not require re-encrypting all data.
- Verify encryption in CI: test TLS enforcement, check LUKS status, and confirm backups stay encrypted.
- Map your setup to Nepal's Privacy Act 2075 and NRB payment guidelines before handling citizen or financial data.
People Also Ask
Is database encryption required by law in Nepal?
The Privacy Act 2075 (2018) requires appropriate security measures for personal data but does not specify exact algorithms. Encryption in transit and at rest is the standard interpretation of "appropriate measures" in privacy impact assessments. Payment processors must also follow NRB security guidelines.
Does Laravel encrypt database connections by default?
No. Laravel 13 passes connection options to PDO, but TLS is off unless you configure SSL attributes in .env. You must enable it on both the database server and the application side with certificate verification enabled.
What is the difference between TDE and application-layer encryption?
TDE encrypts entire database files transparently at the storage engine or filesystem level. Application-layer encryption encrypts specific columns before they reach the database. TDE protects against disk theft; column encryption protects against DBAs with full query access.
Can encrypted database columns be searched or indexed?
Not directly. Encrypted values are opaque to the database engine. Store a separate HMAC hash of the plaintext for equality lookups. Full-text search on encrypted columns requires specialized schemes like deterministic encryption, which has weaker security properties.
Start With TLS, Then Layer At-Rest Controls
Begin with in-transit TLS enforcement—it takes under an hour and closes the highest-risk gap immediately. Then assess at-rest posture based on your hosting environment. Add column encryption only where regulatory or contractual obligations demand it. Document key management before you need it at 3 AM.
If you are building systems that handle sensitive Nepali citizen data or international client information, encryption in transit and at rest should be designed in from day one—not bolted on after an audit finding. Contact us for an encryption architecture review, or reach out directly to discuss your specific requirements.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

