Live
Black Hat USADark ReadingBlack Hat AsiaAI BusinessWhy Today’s AR Displays Fall Short and a 75-Year-Old Idea May Helpeetimes.comTwo Subtle Bugs That Broke Our Remotion Vercel Sandbox (And How We Fixed Them)DEV CommunityZero-Shot Attack Transfer on Gemma 4 (E4B-IT)DEV CommunityGetting Started with the Gemini API: A Practical GuideDEV CommunityLAB: Terraform Dependencies (Implicit vs Explicit)DEV CommunityDesigning a UI That AI Can Actually Understand (CortexUI Deep Dive)DEV CommunityI Went to a Hot Spring via API Call at MidnightDEV CommunityStrong,Perfect,Neon Number ProgramsDEV CommunityThe Mandate Had No Return AddressDEV CommunityCursor AI Review 2026: The Code Editor That Thinks Alongside YouDEV CommunityRescuing 216 Pages from the GeoCities Era: How I Built an HTML-to-Blogger ToolDEV CommunityQ&A: AWS on new AI agents, quantum computing in healthcare - MobiHealthNewsGNews AI quantumBlack Hat USADark ReadingBlack Hat AsiaAI BusinessWhy Today’s AR Displays Fall Short and a 75-Year-Old Idea May Helpeetimes.comTwo Subtle Bugs That Broke Our Remotion Vercel Sandbox (And How We Fixed Them)DEV CommunityZero-Shot Attack Transfer on Gemma 4 (E4B-IT)DEV CommunityGetting Started with the Gemini API: A Practical GuideDEV CommunityLAB: Terraform Dependencies (Implicit vs Explicit)DEV CommunityDesigning a UI That AI Can Actually Understand (CortexUI Deep Dive)DEV CommunityI Went to a Hot Spring via API Call at MidnightDEV CommunityStrong,Perfect,Neon Number ProgramsDEV CommunityThe Mandate Had No Return AddressDEV CommunityCursor AI Review 2026: The Code Editor That Thinks Alongside YouDEV CommunityRescuing 216 Pages from the GeoCities Era: How I Built an HTML-to-Blogger ToolDEV CommunityQ&A: AWS on new AI agents, quantum computing in healthcare - MobiHealthNewsGNews AI quantum
AI NEWS HUBbyEIGENVECTOREigenvector

Nginx + PHP + MySQL Optimisations and Parameter Calculations

DEV Communityby Narendra ChauhanApril 3, 202610 min read1 views
Source Quiz

“Premature optimization is the root of all evil but lack of optimisation is the root of outages.” Table of Contents Introduction Architecture Overview Why Optimisation Is Required Nginx Optimisations Parameter Calculations PHP-FPM Optimisations Parameter Calculations MySQL Optimisations Parameter Calculations System-Level Optimisations (Linux) Practical Example: Small vs Medium vs Large Server Interesting Facts Statistics FAQs Key Takeaways Conclusion 1. Introduction Modern web applications rely heavily on the Nginx + PHP + MySQL (LEMP) stack. While default configurations work for testing, they are not suitable for production traffic. Optimisation ensures: Faster page load time Better concurrency handling Lower memory and CPU usage Higher stability under load This document explains what to

“Premature optimization is the root of all evil but lack of optimisation is the root of outages.”

Table of Contents

  • Introduction

  • Architecture Overview

  • Why Optimisation Is Required

  • Nginx Optimisations & Parameter Calculations

  • PHP-FPM Optimisations & Parameter Calculations

  • MySQL Optimisations & Parameter Calculations

  • System-Level Optimisations (Linux)

  • Practical Example: Small vs Medium vs Large Server

  • Interesting Facts & Statistics

  • FAQs

  • Key Takeaways

  • Conclusion

1. Introduction

Modern web applications rely heavily on the Nginx + PHP + MySQL (LEMP) stack. While default configurations work for testing, they are not suitable for production traffic.

Optimisation ensures:

  • Faster page load time

  • Better concurrency handling

  • Lower memory and CPU usage

  • Higher stability under load

This document explains what to optimise, why to optimise, and how to calculate parameters practically.

2. Architecture Overview

A typical request flow:

  • Client sends HTTP request

  • Nginx handles connection & static content

  • PHP-FPM processes dynamic PHP requests

  • MySQL serves data from database

  • Response sent back to client

Each layer must be tuned together, not individually.

3. Why Optimisation Is Required

Default settings:

  • Are conservative

  • Waste available RAM

  • Limit concurrency

  • Cause slow response under load

Common Problems Without Optimisation

  • 502 / 504 Gateway errors

  • High CPU load

  • PHP-FPM “server reached max_children”

  • MySQL “Too many connections”

4. Nginx Optimisations & Parameter Calculations

Key Nginx Parameters worker_processes auto; worker_connections 4096;

What is worker_processes Number of worker processes Best practice: match CPU cores

nproc Example: 4 CPU cores → worker_processes 4; What is worker_connections Maximum connections per worker

Total Max Connections worker_processes × worker_connections

Example

4 × 4096 = 16,384 concurrent connections

Recommended Extra Optimisations

use epoll; multi_accept on;

sendfile on; tcp_nopush on; tcp_nodelay on;

keepalive_timeout 65; keepalive_requests 1000;`

Enter fullscreen mode

Exit fullscreen mode

5. PHP-FPM Optimisations & Parameter Calculations

Key PHP-FPM Settings

pm = dynamic pm.max_children = 20 pm.start_servers = 5 pm.min_spare_servers = 5 pm.max_spare_servers = 10

Enter fullscreen mode

Exit fullscreen mode

How to Calculate pm.max_children

  • Find average PHP process memory: ps -ylC php-fpm --sort:rss

  • Formula: Available RAM for PHP / Avg PHP process size

Example

  • Available RAM: 2 GB

  • Avg PHP process: 100 MB

2048 / 100 ≈ 20 pm.max_children = 20

Other Important PHP Optimisations

request_terminate_timeout = 60 max_execution_time = 60 memory_limit = 256M

Enter fullscreen mode

Exit fullscreen mode

Enable OPcache

opcache.enable=1 opcache.memory_consumption=256 opcache.max_accelerated_files=20000

Enter fullscreen mode

Exit fullscreen mode

6. MySQL Optimisations & Parameter Calculations

Key MySQL Parameters

innodb_buffer_pool_size = 2G innodb_buffer_pool_instances = 2 max_connections = 200

Enter fullscreen mode

Exit fullscreen mode

How to Calculate innodb_buffer_pool_size

  • Allocate 60–70% of total RAM (dedicated DB server)

Example

  • Server RAM: 4 GB

4 × 70% ≈ 2.8 GB Use 2G or 3G

Connection Calculation

Additional Recommended Settings

query_cache_type = 0 slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 2

Enter fullscreen mode

Exit fullscreen mode

7. System-Level Optimisations (Linux)

File Descriptors

ulimit -n 100000

Kernel Tuning

net.core.somaxconn = 65535 net.ipv4.tcp_max_syn_backlog = 65535 vm.swappiness = 10

8. Practical Server Size Examples

Small Server (2 CPU / 2 GB RAM)

  • Nginx workers: 2

  • worker_connections: 2048

  • PHP max_children: 10

  • MySQL buffer pool: 1G

Medium Server (4 CPU / 8 GB RAM)

  • Nginx workers: 4

  • worker_connections: 4096

  • PHP max_children: 30–40

  • MySQL buffer pool: 4–5G

Large Server (8 CPU / 16 GB RAM)

  • Nginx workers: 8

  • worker_connections: 8192

  • PHP max_children: 60–80

  • MySQL buffer pool: 10–12G

Practical Demonstration (Images Explained)

Step 1. NGINX OPTIMISATION

Parameter Calculations Step 1.1 Backup current nginx.conf

sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak

Enter fullscreen mode

Exit fullscreen mode

Step 1.2 Check current config

cat /etc/nginx/nginx.conf

Enter fullscreen mode

Exit fullscreen mode

Screenshot: Current state before changes

Step 1.3 Edit nginx.conf

sudo nano /etc/nginx/nginx.conf

Enter fullscreen mode

Exit fullscreen mode

Replace/update with this optimized config:

user www-data;  worker_processes 2; # = nproc (2 cores)  worker_rlimit_nofile 65535;  pid /run/nginx.pid;  include /etc/nginx/modules-enabled/*.conf;*

events { worker_connections 1024; # 2 x 1024 = 2048 total connections use epoll; # Linux best event model multi_accept on; # Accept multiple connections at once }

http {

Basic Settings

sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 30; # Reduced from default 75s keepalive_requests 100; types_hash_max_size 2048; server_tokens off; # Hide nginx version

client_max_body_size 20m; client_body_buffer_size 128k; client_header_buffer_size 1k; large_client_header_buffers 4 8k; client_body_timeout 12; client_header_timeout 12; send_timeout 10;

include /etc/nginx/mime.types; default_type application/octet-stream;

Logging Settings

access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log warn; # Only warn+ to reduce I/O

Gzip Settings

gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 3; # Level 3 = good ratio, low CPU gzip_min_length 1024; # Don't compress tiny files gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css text/javascript application/javascript application/json application/xml image/svg+xml font/woff2;

Open File Cache

open_file_cache max=1000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on;

FastCGI Cache (optional - enable per site)

fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=PHPCACHE:10m max_size=100m inactive=60m use_temp_path=off;

include /etc/nginx/conf.d/.conf; include /etc/nginx/sites-enabled/; }`

Enter fullscreen mode

Exit fullscreen mode

Step 1.4 Create FastCGI cache directory

sudo mkdir -p /var/cache/nginx  sudo chown www-data:www-data /var/cache/nginx

Enter fullscreen mode

Exit fullscreen mode

Step 1.5 Test and reload Nginx

sudo nginx -t  sudo systemctl reload nginx

Enter fullscreen mode

Exit fullscreen mode

Screenshot: nginx -t showing syntax is ok and test is successful

Step 1.6 Verify Nginx is running with new settings

sudo nginx -T | grep -E "worker_processes|worker_connections|gzip|keepalive_timeout" systemctl status nginx

Enter fullscreen mode

Exit fullscreen mode

Screenshot: Running status + key parameters

Step 2. PHP-FPM OPTIMISATION

Parameter Calculations Available RAM for PHP-FPM: ~150MB (conservative, leaving room for MySQL + Nginx) Average PHP-FPM process size: ~30-40MB Formula: pm.max_children = 150 / 35 ≈ 4

PHP-FPM Parameters Calculation pm Formula: Dynamic (best for variable traffic) Value: dynamic

pm.max_children Formula: 150MB ÷ 35MB/process Value: 4

pm.start_servers Formula: pm.max_children / 2 Value: 2

pm.min_spare_servers Formula: pm.start_servers / 2 Value: 1

pm.max_spare_servers Formula: pm.start_servers Value: 2

pm.max_requests Formula: Prevent memory leaks Value: 500

Step 2.1 Check PHP-FPM version path

php -v  ls /etc/php/

Enter fullscreen mode

Exit fullscreen mode

Step 2.2 Backup pool config

sudo cp/etc/php/8.4/fpm/pool.d/www.conf/etc /php/8.4/fpm/pool.d/www.conf.bak sudo cp /etc/php/8.4/fpm/php.ini /etc/php/8.4/fpm/php.ini.bak

Enter fullscreen mode

Exit fullscreen mode

Step 2.3 Check current PHP process memory usage

  • Run this to see actual PHP-FPM process sizes

ps aux | grep php-fpm | grep -v grep | awk '{sum += $6} END {print "Total RSS:", sum/1024, "MB"; print "Count:", NR; print "Avg per process:", sum/NR/1024, "MB"}'

Enter fullscreen mode

Exit fullscreen mode

Screenshot: Current process sizes.

Step 2.4 Edit PHP-FPM pool config

sudo nano /etc/php/8.4/fpm/pool.d/www.conf

Enter fullscreen mode

Exit fullscreen mode

Find and update these values (search with Ctrl+W in nano):

[www] user = www-data group = www-data

listen = /run/php/php8.4-fpm.sock listen.owner = www-data listen.group = www-data

pm = dynamic pm.max_children = 4 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 2 pm.max_requests = 500 ;Restart workers after 500 requests (prevents memory leaks) pm.process_idle_timeout = 10s

pm.status_path = /status ; Enable FPM status page ping.path = /ping

slowlog = /var/log/php8.4-fpm-slow.log request_slowlog_timeout = 5s ; Log requests taking > 5 seconds security.limit_extensions = .php`

Enter fullscreen mode

Exit fullscreen mode

Step 2.5 Tune PHP OPcache sudo nano /etc/php/8.4/mods-available/opcache.ini

zend_extension=opcache

; Enable OPcache opcache.enable=1 opcache.enable_cli=0

; Memory: 64MB for low-RAM server opcache.memory_consumption=64 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=10000

; Production settings (set validate_timestamps=0 in prod) opcache.validate_timestamps=1 opcache.revalidate_freq=60

opcache.save_comments=1 opcache.max_wasted_percentage=10 opcache.use_cwd=1

; JIT (PHP 8.x feature) opcache.jit_buffer_size=32M opcache.jit=1255`

Enter fullscreen mode

Exit fullscreen mode

Step 2.6 Tune PHP.ini key values sudo nano /etc/php/8.4/fpm/php.ini

Find and update:  ; Memory limit per PHP process  memory_limit = 128M

; Upload/POST limits upload_max_filesize = 20M post_max_size = 25M max_execution_time = 60 max_input_time = 60

; Error handling (production) display_errors = Off log_errors = On error_log = /var/log/php_errors.log

; Session handling session.gc_maxlifetime = 1440 session.cookie_httponly = 1 session.cookie_secure = 1

; Disable dangerous functions disable_functions = exec,passthru,shell_exec,system,proc_open,popen`

Enter fullscreen mode

Exit fullscreen mode

Step 2.7 Restart PHP-FPM and verify

sudo php-fpm8.4 -t  sudo systemctl restart php8.4-fpm  sudo systemctl status php8.4-fpm

Enter fullscreen mode

Exit fullscreen mode

Screenshot: PHP-FPM status showing active (running)

Step 2.8 Verify OPcache is active

php -r "var_dump(opcache_get_status());" | head -30

Enter fullscreen mode

Exit fullscreen mode

  • or check via CLI

php -i | grep -E "opcache|OPcache"

Enter fullscreen mode

Exit fullscreen mode

Screenshot: OPcache enabled status

Step 2.9 Check PHP-FPM processes after restart

ps aux | grep php-fpm | grep -v grep

Enter fullscreen mode

Exit fullscreen mode

  • Should show master + 2 worker processes (pm.start_servers=2)

Screenshot: FPM process list

Step 3. MYSQL OPTIMISATION

Parameter Calculations

RAM budget for MySQL: ~200MB (out of 914MB total)

innodb_buffer_pool_size Formula: ~20% of RAM (shared server) Value: 192M

innodb_buffer_pool_instances Formula: buffer_pool ÷ 128M Value: 1

max_connections Formula: Low RAM = conservative Value: 50

innodb_log_file_size Formula: 25% of buffer pool Value: 48M

tmp_table_size Formula: Memory temporary tables Value: 16M

max_heap_table_size Formula: Same as tmp_table_size Value: 16M

thread_cache_size Formula: Reuse threads Value: 8

table_open_cache Formula: Open tables cache Value: 400

Step 3.1 Check current MySQL config and status

sudo cp /etc/mysql/mysql.conf.d/mysqld.cnf /etc/mysql/mysql.conf.d/mysqld.cnf.bak

Enter fullscreen mode

Exit fullscreen mode

  • Check current variables

mysql -u root -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool%';"  mysql -u root -p -e "SHOW VARIABLES LIKE 'max_connections';"  mysql -u root -p -e "SHOW STATUS LIKE 'Threads_connected';"

Enter fullscreen mode

Exit fullscreen mode

Screenshot: Current MySQL variables

Step 3.2 Check actual MySQL memory usage

mysql -u root -p -e "  SELECT  ROUND(@@innodb_buffer_pool_size/1024/1024, 0) AS 'Buffer Pool MB',  ROUND(@@key_buffer_size/1024/1024, 0) AS 'Key Buffer MB',  @@max_connections AS 'Max Connections',  @@thread_stack/1024 AS 'Thread Stack KB';  "

Enter fullscreen mode

Exit fullscreen mode

Screenshot: Current MySQL memory config

Step 3.3 Edit MySQL config

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

Enter fullscreen mode

Exit fullscreen mode

Add/update under [mysqld]:

[mysqld]  pid-file = /var/run/mysqld/mysqld.pid  socket = /var/run/mysqld/mysqld.sock  datadir = /var/lib/mysql  log-error = /var/log/mysql/error.log

===== MEMORY SETTINGS =====

Server has 914MB RAM - allocate ~200MB for MySQL

innodb_buffer_pool_size = 192M # Main InnoDB cache (most important!) innodb_buffer_pool_instances = 1 # 1 instance (< 1GB pool) innodb_log_file_size = 48M # ~25% of buffer pool innodb_log_buffer_size = 8M innodb_flush_log_at_trx_commit = 2 # Slight risk, big perf gain (use 1 for strict ACID)

===== CONNECTION SETTINGS =====

max_connections = 50 # Low RAM = keep connections limited thread_cache_size = 8 # Reuse threads, avoid creation overhead wait_timeout = 120 # Kill idle connections after 2 min interactive_timeout = 120

===== QUERY CACHE (removed in MySQL 8.0, skip) =====

MySQL 8.0 removed query_cache - use ProxySQL or app-level cache

===== TABLE CACHE =====

table_open_cache = 400 table_definition_cache = 400

===== TEMP TABLES =====

tmp_table_size = 16M max_heap_table_size = 16M

===== InnoDB I/O =====

innodb_file_per_table = 1 innodb_flush_method = O_DIRECT # Avoid double buffering with OS cache innodb_read_io_threads = 2 # = CPU cores innodb_write_io_threads = 2 # = CPU cores

===== SLOW QUERY LOG =====

slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 2 # Log queries > 2 seconds log_queries_not_using_indexes = 1

===== BINARY LOG (disable if not using replication) =====

skip-log-bin # Uncomment if no replication needed`

Enter fullscreen mode

Exit fullscreen mode

Step 3.4 Validate and restart MySQL

sudo mysqld --validate-config  sudo systemctl restart mysql  sudo systemctl status mysql

Enter fullscreen mode

Exit fullscreen mode

Screenshot: MySQL status active

Step 3.5 Verify new MySQL variables

mysql -u root -p -e "  SELECT 'innodb_buffer_pool_size' AS Variable,  ROUND(@@innodb_buffer_pool_size/1024/1024,0) AS 'Value (MB)'  UNION SELECT 'max_connections', @@max_connections  UNION SELECT 'innodb_log_file_size MB', ROUND(@@innodb_log_file_size/1024/1024,0)  UNION SELECT 'tmp_table_size MB', ROUND(@@tmp_table_size/1024/1024,0)  UNION SELECT 'thread_cache_size', @@thread_cache_size;  "

Enter fullscreen mode

Exit fullscreen mode

Screenshot: New values confirmed

Step 3.6 Check MySQL memory usage post-restart

free -h  ps aux | sort -k6 -rn | head -10

Enter fullscreen mode

Exit fullscreen mode

Screenshot: Overall memory after all services tuned

“Measure first, tune second, and monitor always.”

Step 4. FINAL VERIFICATION

Step 4.1 Check all services running

systemctl status nginx php8.4-fpm mysql --no-pager

Enter fullscreen mode

Exit fullscreen mode

Step 4.2 Full memory picture

free -h  ps aux --sort=-%mem | head -15

Enter fullscreen mode

Exit fullscreen mode

Step 4.3 Check nginx + PHP working together

Test nginx config is still valid  sudo nginx -t

Test PHP-FPM socket exists ls -la /run/php/php8.4-fpm.sock

Check FPM status (if you added status page to your site config) curl http://localhost/status`

Enter fullscreen mode

Exit fullscreen mode

Step 4.4 Check MySQL slow log is active

mysql -u root -p -e "SHOW VARIABLES LIKE 'slow_query%';"

Enter fullscreen mode

Exit fullscreen mode

Step 4.5 Final health summary

echo "=== NGINX ===" && nginx -v && systemctl is-active nginx  echo "=== PHP-FPM ===" && php -v | head -1 && systemctl is-active php8.4-fpm  echo "=== MYSQL ===" && mysql --version && systemctl is-active mysql  echo "=== MEMORY ===" && free -h

Enter fullscreen mode

Exit fullscreen mode

Screenshot: Final health check

Your server is fully optimised. All phases verified:

  • Phase 0 Swap 2GB active

  • Phase 1 Nginx tuned

  • Phase 2 PHP-FPM + OPcache + JIT enabled

  • Phase 3 MySQL InnoDB / connections / slow query log active

9. Interesting Facts & Statistics

  • 1 second delay can reduce conversions by 7%

  • OPcache can improve PHP performance by 2–3×

  • MySQL buffer pool cache hit ratio above 99% is ideal

  • Nginx handles 10× more concurrent connections than traditional servers

11. FAQs

Q1. Should I optimise Nginx, PHP, or MySQL first? Start with PHP-FPM and MySQL, then tune Nginx.

Q2. Can wrong tuning crash the server? Yes. Over-allocating RAM causes OOM kills.

Q3. Are these values fixed forever? No. Recalculate after traffic growth.

Q4. Do I need load testing? Yes. Use tools like ab, wrk, or k6.

12. Key Takeaways

  • Optimisation is calculation-based, not guesswork

  • PHP-FPM memory calculation is critical

  • MySQL buffer pool has the biggest performance impact

  • Nginx handles concurrency, not application logic

  • Monitoring is mandatory after tuning

13. Conclusion

Optimising Nginx + PHP + MySQL is not about copying configs from the internet—it is about understanding server resources, calculating limits, and balancing load across layers. A well-optimised stack:

  • Handles higher traffic

  • Reduces downtime

  • Improves user experience

  • Saves infrastructure cost

About the Author:Narendra is a DevOps Engineer at AddWebSolution, specializing in automating infrastructure to improve efficiency and reliability.

Was this article helpful?

Sign in to highlight and annotate this article

AI
Ask AI about this article
Powered by Eigenvector · full article context loaded
Ready

Conversation starters

Ask anything about this article…

Daily AI Digest

Get the top 5 AI stories delivered to your inbox every morning.

More about

modelavailableversion

Knowledge Map

Knowledge Map
TopicsEntitiesSource
Nginx + PHP…modelavailableversionupdateproductapplicationDEV Communi…

Connected Articles — Knowledge Graph

This article is connected to other articles through shared AI topics and tags.

Knowledge Graph100 articles · 197 connections
Scroll to zoom · drag to pan · click to open

Discussion

Sign in to join the discussion

No comments yet — be the first to share your thoughts!

More in Products