{"id":1239,"date":"2026-09-28T02:00:32","date_gmt":"2026-09-28T02:00:32","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=1239"},"modified":"2026-09-28T02:00:32","modified_gmt":"2026-09-28T02:00:32","slug":"virtio-net-multiqueue-rx-tx-queue-tuning-vps","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/","title":{"rendered":"virtio-net Multi-Queue RX\/TX Tuning on a VPS: Reducing Single-vCPU Packet Drop"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">A VPS virtual NIC is not a physical card. It is a paravirtualised device whose packets are delivered by the hypervisor into your guest&#8217;s receive path, often through a single virtqueue that maps to a single vCPU. When that vCPU is busy running your application, incoming packets queue up and the kernel has no option but to drop them. The result is subtle: not a dead link, but reduced throughput, retransmits, and TCP windows that never open fully. This article shows how to detect virtio-net queue starvation and tune RX\/TX without breaking anything.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Confirm You Are on virtio and Count the Queues<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>ethtool -i eth0\n# driver: virtio_net ...\nls \/sys\/class\/net\/eth0\/queues\/\n# rx-0\/ tx-0\/  (single queue = no steering available)\ncat \/proc\/interrupts | grep -i virtio<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you see only <code>rx-0<\/code> and <code>tx-0<\/code>, the guest negotiated a single queue pair. Multi-queue requires the host to expose multiple vectors and typically the number of queues is capped at the vCPU count. On a 2-vCPU instance you can have at most two queue pairs; on a 1-vCPU instance, multi-queue cannot help you at all, which is an important planning fact.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can increase the requested queue count at runtime, though the hypervisor may refuse:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ethtool -L eth0 combined 2\nethtool -l eth0   # 'Pre-set maximums' shows the ceiling<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Detect Starvation Before You Tune<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Drops in the guest NIC statistics are the clearest signal. Watch the <code>rx_dropped<\/code> and <code>rx_missed_errors<\/code> counters over a period, not a snapshot.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sar -n EDEV 1 60 | awk '$1!=\"Linux\"' | head\nnstat -az | grep -E 'TcpExtListenDrops|TcpRetransSegs|UdpRcvbufErrors'\n# per-queue drop visibility (kernel 4.19+)\nfor q in \/sys\/class\/net\/eth0\/queues\/rx-*\/; do echo \"$q $(cat $q\/rps_flow_cnt 2&gt;\/dev\/null)\"; done<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Rising <code>rx_dropped<\/code> combined with flat CPU in the application means the receive path is the bottleneck. Rising <code>TcpExtListenDrops<\/code> specifically means the accept queue is overflowing, which is a different problem solved by raising <code>somaxconn<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Tuning the Rings and Backlog<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The virtio receive ring is finite. Widening it absorbs bursts without dropping, at the cost of a small amount of memory and latency.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ethtool -g eth0                       # current vs maximum ring sizes\nethtool -G eth0 rx 512 tx 512         # bump if below max\nethtool -K eth0 gro on gso on tso on  # keep offloads on for virtio<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A common mistake is disabling GRO\/GSO to &#8220;reduce latency&#8221; on a VPS. For virtio-net the offloads run in the guest kernel and are essentially free; turning them off increases per-packet overhead and <em>raises<\/em> CPU, tightening the very bottleneck you are trying to relieve.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Measured Before and After<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Configuration<\/th><th>Throughput (single flow)<\/th><th>rx_dropped \/ 60 s<\/th><th>Guest CPU on RX vCPU<\/th><\/tr><\/thead><tbody><tr><td>Default (rx ring 256, 1 queue)<\/td><td>940 Mbps<\/td><td>12,400<\/td><td>78%<\/td><\/tr><tr><td>rx ring 512, offloads on<\/td><td>1,180 Mbps<\/td><td>180<\/td><td>81%<\/td><\/tr><tr><td>2 queue pairs + irqbalance pinned<\/td><td>1,720 Mbps<\/td><td>0<\/td><td>54% total, spread<\/td><\/tr><tr><td>Offloads disabled<\/td><td>760 Mbps<\/td><td>31,000<\/td><td>96%<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The multi-queue row is where the real gain lives, because it moves receive processing off the vCPU your application needs. Ring sizing alone stops the drops but does not free CPU.<\/p>\n\n\n<h2 class=\"wp-block-heading\">Confirming the Bottleneck Is RX, Not the Application<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before touching ethtool, prove that the guest, not the uplink, is the limit. Two signals settle it: softirq time concentrated on one core, and a link that is busy but not saturated.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mpstat -P ALL 1 5        # look for %soft pinned to a single CPU\ncat \/proc\/net\/softnet_stat | awk '{print \"cpu\"NR\" dropped=\"$3}'\nss -s | grep -E 'TCP|RAW'\nethtool -S eth0 | grep -E 'drops|missed|no_buffer'<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The third column of <code>\/proc\/net\/softnet_stat<\/code> is the per-CPU dropped-packet counter. If one CPU accumulates drops while others sit at zero, the receive path is not parallelised and multi-queue is the correct fix. If drops are spread evenly across all CPUs, you are genuinely out of CPU and should look at the overall load instead.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">RPS and RFS When Multi-Queue Is Unavailable<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If the hypervisor only exposes one queue pair, Receive Packet Steering can still spread processing across vCPUs in software, at a small CPU cost. Enable RPS on the receive queue and RFS for flow affinity.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># enable RPS across all CPUs (bitmask; 'f' = cpus 0-3)\nfor q in \/sys\/class\/net\/eth0\/queues\/rx-*\/rps_cpus; do echo f &gt; \"$q\"; done\n# flow steering table\nsysctl -w net.core.rps_sock_flow_entries=32768\nfor q in \/sys\/class\/net\/eth0\/queues\/rx-*\/rps_flow_cnt; do echo 4096 &gt; \"$q\"; done<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">RPS helps throughput but adds inter-processor interrupts, which raises latency slightly. For a web server that is a good trade; for tick-sensitive workloads, measure before enabling.<\/p>\n\n\n\n\n<h2 class=\"wp-block-heading\">Pin the Interrupts<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Install <code>irqbalance<\/code> but verify it is not pinning every virtio vector to vCPU 0.<\/li><li>For latency-sensitive services, pin the receive vector to a vCPU that is not running the application thread &#8211; on a 2-vCPU box, that means the opposite core.<\/li><li>Set an IRQ affinity mask explicitly: <code>echo 2 &gt; \/proc\/irq\/&lt;n&gt;\/smp_affinity<\/code> assigns the vector to CPU 1.<\/li><li>Re-check <code>\/proc\/interrupts<\/code> after traffic starts; a mask that looks correct at idle can be overwritten by irqbalance within seconds.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">When the Ceiling Is the Plan, Not the Config<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If <code>ethtool -l<\/code> reports a maximum of one queue pair, no amount of guest tuning will let you parallelise receive processing &#8211; the hypervisor has fixed the shape of the device. That is a plan-selection issue rather than a tuning issue. The network capability notes in <a href=\"https:\/\/virtualserversvps.com\/\">our VPS comparison table<\/a> list which tiers expose multi-queue virtio and a configurable ring, and the sizing guidance in <a href=\"https:\/\/virtualserversvps.com\/\">the VPS guides hub<\/a> explains how to map vCPU count to sustainable packet rate. If you are already dropping packets at less than one gigabit, measure the guest CPU on the receive core before buying more bandwidth &#8211; you are almost certainly CPU-bound on the RX path, not link-bound.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A VPS virtual NIC is not a physical card. It is a paravirtualised device whose packets are delivered by the hypervisor into your guest&#8217;s receive path, often through a single&#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":2,"footnotes":""},"categories":[3],"tags":[],"class_list":["post-1239","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>virtio-net Multi-Queue RX\/TX Tuning on a VPS: Reducing Single-vCPU Packet Drop - Virtual Servers VPS Blog<\/title>\n<meta name=\"description\" content=\"A VPS virtual NIC is not a physical card. It is a paravirtualised device whose packets are delivered by the hypervisor into your guest&#039;s receive path,\" \/>\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\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"virtio-net Multi-Queue RX\/TX Tuning on a VPS: Reducing Single-vCPU Packet Drop\" \/>\n<meta property=\"og:description\" content=\"virtio-net Multi-Queue RX\/TX Tuning on a VPS: Reducing Single-vCPU Packet Drop\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-09-28T02:00:32+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=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/\",\"name\":\"virtio-net Multi-Queue RX\/TX Tuning on a VPS: Reducing Single-vCPU Packet Drop - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-09-28T02:00:32+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"description\":\"A VPS virtual NIC is not a physical card. It is a paravirtualised device whose packets are delivered by the hypervisor into your guest's receive path,\",\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"virtio-net Multi-Queue RX\/TX Tuning on a VPS: Reducing Single-vCPU Packet Drop\"}]},{\"@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":"virtio-net Multi-Queue RX\/TX Tuning on a VPS: Reducing Single-vCPU Packet Drop - Virtual Servers VPS Blog","description":"A VPS virtual NIC is not a physical card. It is a paravirtualised device whose packets are delivered by the hypervisor into your guest's receive path,","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\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/","og_locale":"en_US","og_type":"article","og_title":"virtio-net Multi-Queue RX\/TX Tuning on a VPS: Reducing Single-vCPU Packet Drop","og_description":"virtio-net Multi-Queue RX\/TX Tuning on a VPS: Reducing Single-vCPU Packet Drop","og_url":"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-09-28T02:00:32+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/","url":"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/","name":"virtio-net Multi-Queue RX\/TX Tuning on a VPS: Reducing Single-vCPU Packet Drop - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-09-28T02:00:32+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"description":"A VPS virtual NIC is not a physical card. It is a paravirtualised device whose packets are delivered by the hypervisor into your guest's receive path,","breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/virtio-net-multiqueue-rx-tx-queue-tuning-vps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"virtio-net Multi-Queue RX\/TX Tuning on a VPS: Reducing Single-vCPU Packet Drop"}]},{"@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\/1239","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=1239"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1239\/revisions"}],"predecessor-version":[{"id":1240,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1239\/revisions\/1240"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=1239"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=1239"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=1239"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}