{"id":764,"date":"2026-08-01T02:24:56","date_gmt":"2026-08-01T02:24:56","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=764"},"modified":"2026-08-18T22:14:51","modified_gmt":"2026-08-18T22:14:51","slug":"linux-io-scheduler-tuning-database-vps","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/","title":{"rendered":"I\/O Scheduler Tuning on a Cloud VPS: What Moves the Needle and What Doesn&#8217;t"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">If you cut your teeth on bare-metal servers, you remember the elevator tuning ritual: deadline for databases, noop for SSDs, BFQ for desktops. On a cloud VPS, that instinct mostly wastes your time \u2014 because the guest never sees a real disk. The I\/O scheduler in your VM&#8217;s kernel reorders requests that are about to be shoved through a virtual queue into a hypervisor that does the real scheduling. This article explains what the scheduler actually does on a virtio-blk device, when it still matters, and where your tuning effort belongs instead.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What your VPS actually presents to the kernel<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>lsblk -d -o NAME,ROTA,TRAN\n# NAME    ROTA TRAN\n# vda        0 virtio\n\ncat \/sys\/block\/vda\/queue\/scheduler\n# [mq-deadline] none<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Three things jump out: the device is <code>virtio<\/code> (a paravirtualized block device), it is non-rotational (<code>ROTA 0<\/code>), and the default scheduler on modern kernels is <code>mq-deadline<\/code> with <code>none<\/code> as the alternative. There is no BFQ in sight unless your provider passes through a real NVMe controller \u2014 which is rare on budget and mid-range VPS plans.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why the guest scheduler barely matters<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">On a physical box, the scheduler&#8217;s job is to merge adjacent requests and reorder them to minimize head movement \u2014 a big deal for spinning disks, a smaller deal for SSDs. Inside a VM, in-flight requests are limited by the virtio ring (typically 128 entries), and the hypervisor performs merging and scheduling on the host side, where it sees the real storage. Your guest scheduler can only reorder the requests sitting in its own small queue, so its impact on total throughput is a few percent at most. Anyone promising large gains from switching a cloud VPS to <code>none<\/code> is selling something.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The one place the guest queue can bite is at very high queue depth: bulk imports, analytics jobs, or a database checkpoint writing hundreds of MB at once. If <code>iostat<\/code> shows <code>avgqu-sz<\/code> pinned at the queue limit with utilization near 100%, the guest queue \u2014 not the storage \u2014 is the bottleneck. That is the scenario where <code>none<\/code> can shave a few percent of overhead.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The levers that do exist<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><code>nr_requests<\/code><\/strong> controls how many requests the block layer queues per device. The default of 128\u2013256 is right for most workloads; lowering it to 64 can trim latency spikes when a noisy neighbor saturates the shared storage, and raising it almost never helps on virtio because the ring caps what can actually be in flight.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong><code>iodepth<\/code><\/strong> is the parameter that actually moves numbers \u2014 but it belongs in your benchmark and your database configuration, not in <code>\/sys<\/code>. A MySQL or PostgreSQL instance issuing depth-16 to depth-32 I\/O will behave completely differently from a depth-1 benchmark:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>fio --name=randread --rw=randread --bs=4k --iodepth=32 \\\n    --ioengine=libaio --direct=1 --runtime=60 --numjobs=4 --size=1G<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run that once per scheduler to prove the point to yourself:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>for sched in none mq-deadline; do\n  echo \"$sched\" > \/sys\/block\/vda\/queue\/scheduler\n  fio --name=bench --rw=randread --bs=4k --iodepth=32 \\\n      --ioengine=libaio --direct=1 --runtime=30 --size=512M \\\n      | grep -E 'IOPS|lat'\ndone<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">On a typical virtio disk the IOPS difference lands inside the noise. If you do decide to change the scheduler, make it survive reboots with a udev rule:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># \/etc\/udev\/rules.d\/60-iosched.rules\nACTION==\"add|change\", KERNEL==\"vd*\", ATTR{queue\/scheduler}=\"none\"\nsudo udevadm trigger<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">How to tell if the guest queue is even the bottleneck<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before you touch any knob, confirm the queue is the constraint. <code>iostat -x 5<\/code> gives you the numbers that matter: <code>avgqu-sz<\/code> (average queue length), <code>%util<\/code> (how busy the device reports itself), and <code>await<\/code> (average I\/O time including queueing). On a virtio disk with a 128-entry ring, <code>avgqu-sz<\/code> pinned near 128 with <code>%util<\/code> at 100% and <code>await<\/code> climbing means requests are waiting in the guest \u2014 the point where scheduler and <code>nr_requests<\/code> choices can shave latency. If instead <code>avgqu-sz<\/code> stays low but <code>await<\/code> is high, the storage backend is slow or throttled, and no guest-side setting will fix it \u2014 that&#8217;s a provider conversation, not a kernel one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The same separation applies to <code>vmstat<\/code>: watch the <code>b<\/code> column (processes blocked on I\/O). A few blocked processes during a checkpoint is normal; sustained double digits across all vCPUs points at the storage layer, and it&#8217;s worth re-running your fio baseline against the provider&#8217;s published numbers before you blame your config.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where to spend the tuning time instead<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The scheduler is a five-minute check, not a tuning project. The real wins on cloud storage live in three places:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>The database&#8217;s own I\/O knobs.<\/strong> <code>innodb_io_capacity<\/code> \/ <code>innodb_io_capacity_max<\/code> in MySQL, <code>effective_io_concurrency<\/code> in PostgreSQL, checkpoint intervals, and fsync batching all change real-world throughput on virtual disks.<\/li>\n<li><strong>Filesystem mount options.<\/strong> <code>noatime<\/code> eliminates a write on every read, and a weekly <code>fstrim -av<\/code> keeps the SSD&#8217;s flash translation layer from degrading \u2014 without the overhead of the <code>discard<\/code> mount option on every delete.<\/li>\n<li><strong>Knowing your baseline.<\/strong> If IOPS collapse regardless of scheduler, suspect the provider, not the kernel. Run the same fio job on two candidates and check CPU steal (<code>top<\/code>&#8216;s <code>%st<\/code>) while you are at it \u2014 storage specs vary more between providers than any scheduler setting ever will. We track disk type and performance in <a href=\"https:\/\/virtualserversvps.com\/#providers\">our VPS comparison table<\/a>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Verify the default scheduler is <code>mq-deadline<\/code>, run one fio at realistic depth to know your storage&#8217;s ceiling, then go tune the database. That is the order that produces measurable gains on a VPS.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you cut your teeth on bare-metal servers, you remember the elevator tuning ritual: deadline for databases, noop for SSDs, BFQ for desktops. On a cloud VPS, that instinct mostly&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":6,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-764","post","type-post","status-publish","format-standard","hentry","category-performance-optimization"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.1 (Yoast SEO v26.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>I\/O Scheduler Tuning on a Cloud VPS: What Moves the Needle and What Doesn&#039;t - Virtual Servers VPS Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"I\/O Scheduler Tuning on a Cloud VPS: What Moves the Needle and What Doesn&#039;t\" \/>\n<meta property=\"og:description\" content=\"I\/O Scheduler Tuning on a Cloud VPS: What Moves the Needle and What Doesn&#039;t\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-08-01T02:24:56+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-08-18T22:14:51+00:00\" \/>\n<meta name=\"author\" content=\"Virtual-Servers-Vps-Editor\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Virtual-Servers-Vps-Editor\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/\",\"name\":\"I\/O Scheduler Tuning on a Cloud VPS: What Moves the Needle and What Doesn't - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-08-01T02:24:56+00:00\",\"dateModified\":\"2026-08-18T22:14:51+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"I\/O Scheduler Tuning on a Cloud VPS: What Moves the Needle and What Doesn&#8217;t\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/\",\"name\":\"Virtual Servers VPS Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\",\"name\":\"Virtual-Servers-Vps-Editor\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g\",\"caption\":\"Virtual-Servers-Vps-Editor\"},\"sameAs\":[\"https:\/\/virtualserversvps.com\/blog\"],\"url\":\"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"I\/O Scheduler Tuning on a Cloud VPS: What Moves the Needle and What Doesn't - Virtual Servers VPS Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/","og_locale":"en_US","og_type":"article","og_title":"I\/O Scheduler Tuning on a Cloud VPS: What Moves the Needle and What Doesn't","og_description":"I\/O Scheduler Tuning on a Cloud VPS: What Moves the Needle and What Doesn't","og_url":"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-08-01T02:24:56+00:00","article_modified_time":"2026-08-18T22:14:51+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/","url":"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/","name":"I\/O Scheduler Tuning on a Cloud VPS: What Moves the Needle and What Doesn't - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-08-01T02:24:56+00:00","dateModified":"2026-08-18T22:14:51+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/linux-io-scheduler-tuning-database-vps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"I\/O Scheduler Tuning on a Cloud VPS: What Moves the Needle and What Doesn&#8217;t"}]},{"@type":"WebSite","@id":"https:\/\/virtualserversvps.com\/blog\/#website","url":"https:\/\/virtualserversvps.com\/blog\/","name":"Virtual Servers VPS Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/virtualserversvps.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0","name":"Virtual-Servers-Vps-Editor","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d820b15f1cd028e97610d9adf536df7be5cb6423869967037d468d5355fa003f?s=96&d=mm&r=g","caption":"Virtual-Servers-Vps-Editor"},"sameAs":["https:\/\/virtualserversvps.com\/blog"],"url":"https:\/\/virtualserversvps.com\/blog\/author\/virtualserversvps\/"}]}},"_links":{"self":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/764","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/comments?post=764"}],"version-history":[{"count":2,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/764\/revisions"}],"predecessor-version":[{"id":915,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/764\/revisions\/915"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=764"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=764"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=764"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}