balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
throughput-performance.latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
throughput-performance.latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
throughput-performance.latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
throughput-performance.latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
throughput-performance.latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
throughput-performance.latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
throughput-performance.latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
throughput-performance.latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
throughput-performance.latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
throughput-performance.latency-performance, or a custom profile derived from it.latency-performance plus vm.swappiness=10 and a small swap file — not zero swap.balanced if you chose tuned for performance; that is the distro default and you gain nothing.tuned-adm verify after provisioning and after any cloud-init run.Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.
tuned is one of the most useful and most misunderstood packages on a Linux VPS. It ships a set of named kernel and device profiles — curated bundles of CPU governor, scheduler, virtual memory, disk queue and power settings — and applies them atomically with tuned-adm profile <name>. The misunderstanding is treating profiles as magic performance buttons. They are not: a profile is a bundle of conservative tunings that must match your workload or it will actively hurt you. A database VPS running a web-optimised profile will have the wrong read-ahead and dirty-ratio settings; a web VPS running a throughput profile may hold dirty pages too long and spike latency on small writes.
This article covers the profiles that matter on a VPS, what each one actually changes, how to verify it took effect, and how to build a custom profile that layers your own sysctl values on top. If you have not yet worked through generic kernel tuning, start with our guide to VPS kernel parameter and sysctl tuning, since a tuned profile is just a managed overlay on the same parameters.
What tuned actually does
Installed via apt install tuned (Debian/Ubuntu) or dnf install tuned (RHEL family), tuned runs as a daemon with a profile selected at /etc/tuned/active_profile. On activation it performs three kinds of changes:
- sysctl writes — values like
vm.swappiness,vm.dirty_ratio,vm.dirty_background_ratio,net.ipv4.tcp_*. - Device settings — I/O scheduler on each block device (
/sys/block/*/queue/scheduler), read-ahead (read_ahead_kb), and sometimes queue depth. - Plugin actions — CPU governor and energy/performance preference via the
cpuplugin, disk power management, and in some profiles, transparent hugepage behaviour.
Profiles live in /usr/lib/tuned/<name>/tuned.conf, with local overrides in /etc/tuned/. That split matters: your custom profile in /etc/tuned/ survives package upgrades, edits to /usr/lib/ do not.
Profile comparison for VPS workloads
| Profile | Intended workload | Key vm settings | I/O scheduler | Fit for a VPS |
|---|---|---|---|---|
throughput-performance | Generic server, maximum I/O and CPU | swappiness=10, dirty_ratio=40, dirty_background=10 | mq-deadline / none | Good default for web or general servers |
latency-performance | Latency-sensitive services | swappiness=10, dirty_ratio=10, dirty_background=3 | none / mq-deadline | Best for databases on SSD/NVMe |
network-latency | Network-focused, low per-packet latency | swappiness=10, aggressive THP disabled | unchanged | Useful for proxy/firewall roles |
network-throughput | High bandwidth bulk transfer | large TCP buffers | unchanged | Niche; large socket buffers cost RAM |
virtual-guest | Generic VM guest | moderate swappiness=30 | none | Reasonable starting point, not optimal |
balanced | Default desktop/server mix | swappiness=60, dirty_ratio=20 | mq-deadline | Too conservative for a busy VPS |
powersave | Minimise energy | swappiness=60+ | unchanged | Never on a server |
Two of those rows carry most of the value. throughput-performance is the right starting point for a general web VPS. latency-performance is the right choice when a database shares the box, because it forces dirty pages to disk far more eagerly (dirty_ratio=10 instead of 40), which keeps write latency predictable at the cost of a little raw throughput. On a small NVMe VPS with a 256 MB buffer pool, that trade is almost always correct.
Applying and verifying a profile
tuned-adm profile throughput-performance
tuned-adm active
tuned-adm verify
tuned-adm verify re-reads every setting in the active profile and reports whether the live kernel state matches. If you (or a cloud-init script, or another tuning tool) changed a sysctl after tuned applied, verify will flag the drift. This is the main reason to run tuned rather than a hand-written sysctl file: it detects and can re-assert your configuration.
To see what a profile will change before you apply it:
tuned-adm profile_info latency-performance
tuned-adm recommend
tuned-adm recommend uses the recommend plugin to inspect the host (virt type, whether it is a guest, disk type) and suggest a profile. On a KVM VPS it usually suggests virtual-guest — a safe, unambitious choice you will generally want to override.
Building a custom profile that survives upgrades
The practical pattern is to inherit the closest stock profile and add your own overrides. Create /etc/tuned/vps-db/tuned.conf:
[main]
summary=Database-optimised profile for 2–4 GB VPS
include=latency-performance
[sysctl]
vm.dirty_writeback_centisecs=500
vm.dirty_expire_centisecs=1000
vm.vfs_cache_pressure=50
net.core.somaxconn=1024
[disk]
read_ahead_kb=1024
scheduler=none
Then tuned-adm profile vps-db. The include= line pulls in everything from latency-performance, and your sections override or extend it. Values you do not specify are left as the parent set them.
Two cautions. First, do not set vm.swappiness=0 on a small VPS: with no swap headroom you convert memory pressure directly into OOM kills instead of slow paging. 10 is the practical floor. Second, scheduler=none (or mq-deadline) is correct for SSDs; on spinning disk you want bfq or mq-deadline with a larger read-ahead. You can confirm the device is SSD with cat /sys/block/vda/queue/rotational — 0 means SSD.
Measuring whether it helped
Changing a profile without measuring is guesswork. A minimal before/after check on the database VPS:
sysbench fileio --file-total-size=2G --file-test-mode=rndrw prepare
sysbench fileio --file-total-size=2G --file-test-mode=rndrw --time=60 run
vmstat 1 60 > /tmp/vmstat.after
Watch si/so (swap in/out) and the bo column in vmstat. A latency profile should reduce bursty bo at the cost of slightly higher steady bo. If si/so are non-zero in either run, your working set does not fit in RAM and no tunable profile will fix that — you need a bigger instance or a smaller buffer pool. Our guide to diagnosing VPS disk I/O latency spikes covers how to tell scheduler-caused latency from genuine device saturation.
Practical recommendations
- General web VPS:
throughput-performance. - VPS running MySQL/MariaDB/PostgreSQL:
latency-performance, or a custom profile derived from it. - Tiny 512 MB VPS:
latency-performanceplusvm.swappiness=10and a small swap file — not zero swap. - Never leave the daemon on
balancedif you chose tuned for performance; that is the distro default and you gain nothing. - Always run
tuned-adm verifyafter provisioning and after any cloud-init run.
Finally, remember that tuned does not size your applications. It cannot set an InnoDB buffer pool, an OPcache limit, or a PHP-FPM pool ceiling. Those decisions dominate performance on a small VPS long before kernel tunables do. Treat tuned as the last 5% of tuning, applied after the application layer is correctly sized — not as the first thing you reach for. For a full picture of what to size first, see our Nginx and caching tuning walkthrough.


Leave a Reply
You must be logged in to post a comment.