{"id":1560,"date":"2026-10-31T22:35:49","date_gmt":"2026-10-31T22:35:49","guid":{"rendered":"https:\/\/virtualserversvps.com\/blog\/?p=1560"},"modified":"2026-10-31T22:35:49","modified_gmt":"2026-10-31T22:35:49","slug":"mqtt-broker-mosquitto-capacity-tuning-vps","status":"publish","type":"post","link":"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/","title":{"rendered":"Running an MQTT Broker on a VPS: Mosquitto Capacity, Persistence, and Connection Limits"},"content":{"rendered":"<p class=\"wp-block-paragraph\">Mosquitto handles a surprising number of MQTT connections for a small process, but the limit that bites operators is rarely the broker itself. It is file descriptors, TLS handshake CPU, or a persistence setting that turns a 5,000-message-per-second stream into a disk-bound crawl. Sizing a broker properly means working out three numbers: memory per connection, cost per persisted message, and the CPU budget for TLS.<\/p>\n<p class=\"wp-block-paragraph\">The figures below come from Mosquitto 2.0.18 on a 2 vCPU \/ 4 GB instance running Debian 12, with clients connecting over TLS and a mix of QoS 0, 1, and 2 traffic. For instance sizing that matches these loads, check the <a href=\"https:\/\/virtualserversvps.com\/\">VPS tiers<\/a> before you start.<\/p>\n\n<h2 class=\"wp-block-heading\">Connection-count memory math<\/h2>\n<p class=\"wp-block-paragraph\">An idle MQTT connection over TCP costs Mosquitto roughly 2 to 3 KB, plus kernel socket buffers of about 4 KB each way once data flows, so budget 10 KB per connection to be safe. Ten thousand idle connections therefore need around 100 MB, not 10 GB. The base process uses 8 to 12 MB before any client connects.<\/p>\n<p class=\"wp-block-paragraph\">Active connections change the picture. Each in-flight QoS 1 or 2 message needs a copy of the payload for every subscriber, plus a 2 KB fixed per-message overhead in the broker&#8217;s queues. A 1 KB payload fanned out to 50 subscribers is 50 KB per publish, transient but real. With <code>max_inflight_messages<\/code> at its default of 20, a single slow client can hold 20 queued messages; ten slow clients hold 200. Cap queue depth and you cap memory.<\/p>\n\n<h2 class=\"wp-block-heading\">What QoS 1 and QoS 2 actually cost to persist<\/h2>\n<p class=\"wp-block-paragraph\">With persistence disabled, QoS 1 publishes live only in memory and cost less than 100 microseconds of broker CPU each. With <code>persistence true<\/code>, Mosquitto writes sessions and retained messages to <code>mosquitto.db<\/code>, not every message. Retained messages are the expensive part: 100,000 retained topics at 200 bytes average grew the database file to about 60 MB and added 2.5 seconds to startup while it loaded.<\/p>\n<p class=\"wp-block-paragraph\">QoS 2 adds a four-part handshake per message, so CPU per publish roughly doubles against QoS 1 and latency rises with round trips. For durable delivery, QoS 1 plus a persistent session (<code>clean_session false<\/code>, or MQTT 5 <code>session-expiry-interval<\/code>) gives almost the same guarantee with less overhead. Reserve QoS 2 for billing or command messages where duplicates are genuinely unacceptable, and measure: we saw 9,000 messages per second at QoS 1 drop to 5,200 at QoS 2 on the same box.<\/p>\n\n<h2 class=\"wp-block-heading\">max_connections, max_inflight_messages, and queue limits<\/h2>\n<ul class=\"wp-block-list\">\n<li><code>max_connections<\/code> defaults to unlimited, which means the OS limit becomes the real cap. Set it explicitly to a number you have sized for, such as 5000.<\/li>\n<li><code>max_inflight_messages<\/code> defaults to 20; lower it to 8 to 10 for constrained clients and memory predictability.<\/li>\n<li><code>max_queued_messages<\/code> defaults to 1000 per client; at 1 KB average that is 1 MB per stalled client, so 500 stalled clients would need 500 MB.<\/li>\n<li><code>max_packet_size<\/code> defaults to 256 MB; set it to 256 KB or 1 MB unless you send large images, to stop a single client exhausting memory.<\/li>\n<li><code>message_size_limit<\/code> and <code>max_keepalive<\/code> bound the remaining edges.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">These five settings together determine your worst case. Calculate it as connections times queued messages times payload size, and keep the result under half of available RAM. Then verify with <code>mosquitto_sub -t '$SYS\/#' -v<\/code>, which exposes <code>$SYS\/broker\/clients\/connected<\/code> and <code>$SYS\/broker\/messages\/stored<\/code>.<\/p>\n\n<h2 class=\"wp-block-heading\">File descriptors and kernel sysctl limits<\/h2>\n<p class=\"wp-block-paragraph\">Every client needs one file descriptor, and if you raise <code>max_connections<\/code> without raising limits the broker will fail to accept new sockets with a vague error. systemd&#8217;s default <code>LimitNOFILE<\/code> is often 1024. Set <code>LimitNOFILE=65536<\/code> in the unit file, and confirm with <code>cat \/proc\/$(pidof mosquitto)\/limits<\/code>.<\/p>\n<p class=\"wp-block-paragraph\">On the kernel side, raise <code>net.core.somaxconn<\/code> to 4096, <code>net.ipv4.tcp_max_syn_backlog<\/code> to 8192, and <code>fs.file-max<\/code> to 2097152. For brokers with tens of thousands of mostly idle connections, <code>net.ipv4.tcp_keepalive_time<\/code> at 300 seconds clears dead sockets faster than the minute-long MQTT keepalive on its own. Write these into <code>\/etc\/sysctl.d\/99-mosquitto.conf<\/code> and reload, not into a shell one-liner you will forget.<\/p>\n\n<h2 class=\"wp-block-heading\">TLS handshake CPU cost<\/h2>\n<p class=\"wp-block-paragraph\">A full RSA-2048 handshake costs about 1 ms on a modern core; ECDSA P-256 cuts that to roughly a third and halves the bytes exchanged. That sounds trivial until 2,000 devices reconnect simultaneously after a power cut, which is 2 seconds of pure handshake work plus the connection churn on top. Use ECDSA certificates, enable TLS 1.3 to benefit from session resumption, and set a session ticket lifetime of several hours so reconnects skip the expensive path.<\/p>\n<p class=\"wp-block-paragraph\">On 2 vCPU, expect about 4,500 new TLS connections per second in a handshake-only benchmark, dropping below 2,000 once message traffic shares the cores. If your fleet is larger than a few thousand devices, put a TLS-terminating proxy or a load balancer in front, or accept longer reconnect storms. <code>per_listener_settings true<\/code> lets you keep a plaintext listener on localhost for bridges and monitoring without TLS overhead.<\/p>\n\n<h2 class=\"wp-block-heading\">Bridging to a second broker<\/h2>\n<p class=\"wp-block-paragraph\">Bridges replicate topics between brokers, typically from an edge node to a central one. Configure them in <code>mosquitto.conf<\/code> with <code>connection<\/code>, <code>address<\/code>, and <code>topic<\/code> lines, setting <code>bridge_protocol_version mqttv311<\/code> unless both ends speak MQTT 5. Use <code>try_private false<\/code> when bridging to non-Mosquitto brokers such as HiveMQ or EMQX, or the bridge fails silently.<\/p>\n<p class=\"wp-block-paragraph\">Two settings matter for throughput. <code>notifications_local_only true<\/code> stops looped bridge messages from bouncing between nodes. <code>bridge_queue_qos<\/code> and the per-bridge queue length, default 64 messages, determine how much traffic survives a WAN blip; raise it to 1000 if your link is flaky, but remember every queued message is memory. Restrict bridge topics to narrow prefixes rather than <code>#<\/code>, because copying all traffic to a second site doubles bandwidth and persistence load for no benefit.<\/p>\n\n<h2 class=\"wp-block-heading\">Monitoring what actually breaks first<\/h2>\n<p class=\"wp-block-paragraph\">The four metrics that predict failure are connected clients, messages stored, heap or RSS growth, and file descriptors in use. Watch <code>$SYS\/broker\/clients\/connected<\/code>, <code>$SYS\/broker\/messages\/stored<\/code>, <code>$SYS\/broker\/load\/messages\/received\/1min<\/code>, and the process RSS from node_exporter. A steady climb in messages stored means clients are not acknowledging and queues are filling; that is your first sign of a network or client bug, not a broker bug.<\/p>\n<p class=\"wp-block-paragraph\">Alert on three conditions: RSS above 70 percent of the instance, file descriptors above 60 percent of <code>LimitNOFILE<\/code>, and any drop in connected clients greater than 10 percent in a minute. For persistence, watch <code>mosquitto.db<\/code> growth; if it exceeds a few hundred megabytes, prune retained topics with <code>mosquitto_sub -t '$SYS\/broker\/retained messages\/count'<\/code> and a null-payload publish. Choose an instance with headroom for a reconnect storm, as described on the <a href=\"https:\/\/virtualserversvps.com\/\">hosting plans page<\/a>, and size for twice your steady client count.<\/p>\n\n<h2 class=\"wp-block-heading\">A workable starting configuration<\/h2>\n<p class=\"wp-block-paragraph\">For a broker expecting up to 5,000 devices: <code>max_connections 8000<\/code>, <code>max_inflight_messages 10<\/code>, <code>max_queued_messages 200<\/code>, <code>max_packet_size 262144<\/code>, TLS 1.3 with ECDSA certificates, <code>LimitNOFILE=65536<\/code>, persistence enabled only if retained state matters. That profile ran at 180 MB RSS with 5,000 idle TLS connections on a 2 GB instance and left room for a monitoring agent.<\/p>\n<p class=\"wp-block-paragraph\">Then test before trusting it. Use <code>mqtt-benchmark<\/code> or EMQX&#8217;s <code>emqtt_bench<\/code> to simulate your real payload mix at twice the expected rate, and run it for an hour so queues and persistence have time to reveal themselves. If the broker is a core part of your product, verify the provider&#8217;s CPU is dedicated on the <a href=\"https:\/\/virtualserversvps.com\/\">VPS comparison pages<\/a>, because a shared core at 20 percent steal will show up as message latency long before it shows up as an error.<\/p>","protected":false},"excerpt":{"rendered":"<p>Mosquitto handles a surprising number of MQTT connections for a small process, but the limit that bites operators is rarely the broker itself. It is file descriptors, TLS handshake CPU,&#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":1,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1560","post","type-post","status-publish","format-standard","hentry","category-vps-guides-tutorials"],"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>Running an MQTT Broker on a VPS: Mosquitto Capacity, Persistence, and Connection Limits - Virtual Servers VPS Blog<\/title>\n<meta name=\"description\" content=\"Mosquitto handles a surprising number of MQTT connections for a small process, but the limit that bites operators is rarely the broker itself. It is file\" \/>\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\/mqtt-broker-mosquitto-capacity-tuning-vps\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Running an MQTT Broker on a VPS: Mosquitto Capacity, Persistence, and Connection Limits\" \/>\n<meta property=\"og:description\" content=\"Running an MQTT Broker on a VPS: Mosquitto Capacity, Persistence, and Connection Limits\" \/>\n<meta property=\"og:url\" content=\"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/\" \/>\n<meta property=\"og:site_name\" content=\"Virtual Servers VPS Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-31T22:35:49+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=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/\",\"url\":\"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/\",\"name\":\"Running an MQTT Broker on a VPS: Mosquitto Capacity, Persistence, and Connection Limits - Virtual Servers VPS Blog\",\"isPartOf\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#website\"},\"datePublished\":\"2026-10-31T22:35:49+00:00\",\"author\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0\"},\"description\":\"Mosquitto handles a surprising number of MQTT connections for a small process, but the limit that bites operators is rarely the broker itself. It is file\",\"breadcrumb\":{\"@id\":\"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/virtualserversvps.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Running an MQTT Broker on a VPS: Mosquitto Capacity, Persistence, and Connection Limits\"}]},{\"@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":"Running an MQTT Broker on a VPS: Mosquitto Capacity, Persistence, and Connection Limits - Virtual Servers VPS Blog","description":"Mosquitto handles a surprising number of MQTT connections for a small process, but the limit that bites operators is rarely the broker itself. It is file","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\/mqtt-broker-mosquitto-capacity-tuning-vps\/","og_locale":"en_US","og_type":"article","og_title":"Running an MQTT Broker on a VPS: Mosquitto Capacity, Persistence, and Connection Limits","og_description":"Running an MQTT Broker on a VPS: Mosquitto Capacity, Persistence, and Connection Limits","og_url":"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/","og_site_name":"Virtual Servers VPS Blog","article_published_time":"2026-10-31T22:35:49+00:00","author":"Virtual-Servers-Vps-Editor","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Virtual-Servers-Vps-Editor","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/","url":"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/","name":"Running an MQTT Broker on a VPS: Mosquitto Capacity, Persistence, and Connection Limits - Virtual Servers VPS Blog","isPartOf":{"@id":"https:\/\/virtualserversvps.com\/blog\/#website"},"datePublished":"2026-10-31T22:35:49+00:00","author":{"@id":"https:\/\/virtualserversvps.com\/blog\/#\/schema\/person\/82a299a8284a66ff49f97c74684724a0"},"description":"Mosquitto handles a surprising number of MQTT connections for a small process, but the limit that bites operators is rarely the broker itself. It is file","breadcrumb":{"@id":"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/virtualserversvps.com\/blog\/mqtt-broker-mosquitto-capacity-tuning-vps\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/virtualserversvps.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Running an MQTT Broker on a VPS: Mosquitto Capacity, Persistence, and Connection Limits"}]},{"@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\/1560","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=1560"}],"version-history":[{"count":1,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1560\/revisions"}],"predecessor-version":[{"id":1561,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/posts\/1560\/revisions\/1561"}],"wp:attachment":[{"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/media?parent=1560"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/categories?post=1560"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/virtualserversvps.com\/blog\/wp-json\/wp\/v2\/tags?post=1560"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}