Home › Topics › Bandwidth Management › Throttling

Throttling Transfers at the Client and Server

The quickest fix for a transfer that is flattening the office link is to tell it to slow down. Almost every transfer tool has a switch for this, and some servers can enforce it per account. Both major operating systems can impose it on a process or a port without touching the tool at all. The catch is that the switches all use different units and sit at different places along the path. Each has a failure mode that only shows up after you rely on it.

This article goes through the throttles one by one. It covers what a rate limit actually does and the exact flags in the common command-line tools. It covers the kinds of limit a server can enforce and the operating-system throttles that work on anything. It includes a decision table for where each kind belongs. It closes with the tradeoffs that vendors' documentation leaves out. It is part of our Bandwidth Management series; if you have not yet read why bulk transfers crush the WAN, that article explains the damage a throttle prevents.

What a Throttle Actually Does

A throttle, or rate limit, is a ceiling on how fast a transfer may send. Without one, TCP probes upward until the link is full; with one, the tool stops itself short of that. The link keeps some headroom, the router's queue stays short, and everyone else's packets get through promptly. The transfer takes longer, and that is the entire cost.

Nearly every throttle is built on the same idea, the token bucket, and it is worth understanding because it explains the bursts you will see. Imagine a bucket into which tokens drip at a steady rate — say enough per second to pay for 3.75 megabytes. Every chunk of data the tool sends must spend tokens equal to its size. If the bucket has tokens, the chunk goes immediately; if it is empty, the tool waits until enough have dripped in. Over any long stretch the average rate cannot exceed the drip rate. But because the bucket holds a few seconds' worth of tokens, a tool that has been idle can send a short burst at full speed before it settles down. That is why a throttled transfer's speed graph looks like a spike followed by a flat line.

The other thing to fix in your head before touching a flag is units. Link speeds are in bits per second; most tool limits are in bytes per second, and a few are in bits. Eight bits make a byte. Some tools also count a kilobyte as 1024 bytes (a kibibyte, KiB) and others as a round thousand. That difference is under three percent and does not matter. The bits-versus-bytes difference is a factor of eight and matters enormously. A limit of "3600" that you believed was kilobits but was actually kibibytes lets the transfer run eight times faster than intended. That happens at exactly the moment you told everyone the problem was solved.

Tool and option Unit of the bare number Roughly 30 Mbit/s
rsync --bwlimit= KiB per second (suffixes k, m accepted) --bwlimit=3600
curl --limit-rate Bytes per second (suffixes k, m, g) --limit-rate 3600k
wget --limit-rate= Bytes per second (suffixes k, m) --limit-rate=3600k
scp -l Kilobits per second -l 30000
lftp net:limit-rate Bytes per second (suffixes K, M) set net:limit-rate 3600K
robocopy /IPG: Milliseconds of pause per 64 KB block /IPG:20 (about 3 MB/s; measure it)
Windows QoS policy Bits per second 30000000
Linux tc tbf Explicit: mbit is megabits, mb is megabytes rate 30mbit

The worked figure is the one from the previous article: a 50 Mbit/s branch link, with the daytime backup held to sixty percent of it. That is 30 Mbit/s or 3.75 MB/s. In binary kilobytes that is about 3,660 KiB/s, so a round 3600 is close enough for every tool that counts bytes.

Throttling at the Client: the Flags

Client-side throttling is the easiest to apply because you already own the command. Here are the common tools, each holding the same 30 GB backup to roughly 30 Mbit/s. At that rate the job takes about two hours and thirteen minutes instead of eighty; that is the trade.

# rsync over SSH: --bwlimit is KiB/s unless you add a suffix
rsync -av --bwlimit=3600 /data/backup/ backup@sftp.example.com:/inbound/

# curl upload to SFTP or HTTPS: --limit-rate is bytes/s, k = 1024
curl --limit-rate 3600k -T backup.tar sftp://backup@sftp.example.com/inbound/

# wget download: same convention as curl
wget --limit-rate=3600k https://files.example.com/pub/dataset.tar

# scp: -l is KILOBITS per second, so 30000 = 30 Mbit/s
scp -l 30000 backup.tar backup@sftp.example.com:/inbound/

# lftp: per-connection limit, or a total across all its connections
lftp -e "set net:limit-rate 3600K; set net:limit-total-rate 3600K; \
  put backup.tar -o /inbound/backup.tar; bye" sftp://backup@sftp.example.com

# robocopy to a share over the WAN: pause 20 ms after each 64 KB block
robocopy D:\backup \\filesrv.example.com\inbound /E /IPG:20

A few details behind each line. In rsync, --bwlimit applies to the whole transfer, checksum chatter included, and accepts suffixes such as --bwlimit=3.5m. Our rsync over WAN article covers the other flags that matter on thin links. In curl and wget the limit is enforced by pausing between reads and writes, so the average is accurate but the instantaneous rate wobbles. See curl for file transfer. In scp, -l is the odd one out — kilobits, not kilobytes — as its manual page states. The article on scp command mastery has the rest. In lftp, net:limit-rate limits each connection and net:limit-total-rate caps the sum. That matters because lftp opens several connections in its parallel modes. Download and upload limits can differ by writing 3600K:1200K. lftp power usage has the full list.

robocopy deserves a caution. Its /IPG (inter-packet gap) option does not set a rate; it inserts a pause of the given milliseconds after each 64 KB block. The resulting rate is roughly 64 KB divided by the pause, minus the time each block spends on the wire. So /IPG:20 gives about 3 MB/s on a fast link and less on a slow one. Treat it as a coarse knob: pick a value, measure the actual rate, and adjust. Our robocopy for migrations article covers its other behavior on the WAN.

Graphical clients have the same control under a different name. Look in the transfer settings for "speed limit" or "bandwidth limit," usually in kilobytes per second. Sometimes it has a schedule so it applies only during working hours. FileZilla, for example, has a speed-limits section. Set the limit in the saved site profile rather than the global default, so an exception for one destination does not slow every other transfer.

Where a Throttle Can Sit

The flags above all live inside the transfer tool, but that is only one of five places a limit can be applied. The diagram below traces a transfer from the client application to the server application and marks each point where a throttle can be imposed. The further left, the more cooperative the throttle (the sender chooses to obey it). The further right, the more it is enforced on senders whether they like it or not.

Diagram of a transfer path from client application through the client operating system, the network edge router, the server operating system, and the server application, with five throttle points marked: a tool flag, an OS policy on the client, shaping at the edge, an OS policy on the server, and a per-account limit in the server software.

Points 1, 2, 4 and 5 are this article. Point 3, shaping at the WAN edge, is the network team's territory and has its own article, network-level shaping and QoS. Each point catches a different set of transfers. A tool flag catches one job, and a host policy catches every job on that machine. A server limit catches every client of that server, and the edge catches everything.

Throttling at the Server

Server-side limits apply to every client, including the partner you cannot reconfigure and the colleague who forgot the flag. They come in three shapes, and the difference matters more than it looks.

A per-connection limit caps each data connection separately. It is the most common kind and the weakest. Any client that opens several connections at once gets the limit multiplied by the number of connections. Examples include a graphical client set to four simultaneous transfers, or lftp with its parallel mode. A per-connection cap of 1 MB/s with eight connections is an 8 MB/s cap, which on a 50 Mbit/s link is no cap at all.

A per-account limit caps the total for a user regardless of how many connections they open. This is what you want for a partner or a service account, and it is the setting to look for first in your server's documentation. Some servers offer it directly. Others offer only a per-connection cap plus a maximum number of connections per account. Multiplied together, these give an effective per-account ceiling. That combination is covered from the capacity side in our Server Capacity and Concurrency series.

A global limit caps the server's total sending or receiving rate. It protects the server's own link from the sum of all clients, but it says nothing about fairness between them. One aggressive client can still take most of the global allowance. Global limits are a safety net, not a policy.

Where the settings live varies by server. Traditional FTP servers on Linux usually expose per-user rate directives in their configuration file. For instance, vsftpd has a local_max_rate value in bytes per second per session. OpenSSH's SFTP subsystem has no rate limit of its own, which surprises people. On an SFTP server built on OpenSSH the limit has to come from the operating system, covered next. On Windows servers, check the per-account or per-group settings in the management interface. If there is no rate setting, the operating-system policy below applies to any Windows server process.

Remember: a per-connection limit is not a per-account limit. Before you trust a server-side cap, open four connections from a test client and confirm the total stays under the number you set. If it does not, add a connection limit per account or move the throttle to the operating system.

Operating-System Throttles That Work on Anything

When the tool has no flag and the server has no setting, the operating system can impose a limit on a process, a port, or an interface. These throttles are enforced, not voluntary, and they cover every tool on the machine.

Windows: a QoS policy with a throttle rate

Windows has a built-in policy engine that can mark and throttle outbound traffic per application or port. It is managed with PowerShell or through Group Policy, and the throttle value is in bits per second, so 30 Mbit/s is written as thirty million:

# Throttle everything sftp.exe sends to 30 Mbit/s (value is BITS per second)
New-NetQosPolicy -Name "BulkSFTP" -AppPathNameMatchCondition "sftp.exe" `
  -ThrottleRateActionBitsPerSecond 30000000 -NetworkProfile All

# Or throttle by destination port instead of by program
New-NetQosPolicy -Name "BulkPort22" -IPProtocolMatchCondition TCP `
  -IPDstPortMatchCondition 22 -ThrottleRateActionBitsPerSecond 30000000

# Check, and remove when done
Get-NetQosPolicy
Remove-NetQosPolicy -Name "BulkSFTP" -Confirm:$false

The policy applies to traffic leaving this machine, which is the direction you normally need to control. Matching on the program path is convenient on a client; on a server, match the source port your service listens on instead. The same policy engine can also mark packets so the network gives them lower priority; that side is explained in the QoS article.

Linux: tc with a token bucket

On Linux the traffic-control tool tc attaches a queueing discipline to an interface. The simplest one, tbf (token bucket filter), is exactly the bucket described earlier, applied to everything the interface sends:

# Cap all outbound traffic on eth0 at 30 Mbit/s
tc qdisc add dev eth0 root tbf rate 30mbit burst 64kb latency 400ms

# See it working (bytes sent, packets dropped or delayed)
tc -s qdisc show dev eth0

# Remove it
tc qdisc del dev eth0 root

Here rate is the drip rate. The burst value is the bucket size in bytes (kb means kilobytes; kbit would mean kilobits). The latency value is the longest a packet may wait before tc drops it. This throttle caps the entire interface, so it belongs on a dedicated transfer host. Limiting one port or destination while leaving the rest alone needs classes and filters, which the QoS article shows with a short example. Note too that tc shapes only what the interface sends; to slow what a Linux box receives, throttle at the sending end.

Where Each Throttle Belongs

With five places to put a limit, the question is which one to use. The decision table below matches the common situations to the throttle that fits.

Situation Best place for the throttle Why
One scripted job you control Tool flag in the script Cheapest, visible in the job, easy to change per run
Several jobs on one transfer host Host policy (Windows QoS, tc) One cap covers every tool and every future job on that machine
Partners uploading to your server Per-account limit on the server You cannot configure their client; the account is the handle you own
Users with graphical clients on laptops Server per-account limit, then network shaping Client settings will be changed or forgotten; enforce where they cannot
Many tools, many hosts, one thin link Shaping at the WAN edge The only point that sees everything; needs the network team
Job must finish by a deadline Reschedule off-peak instead of throttling A throttle makes it slower; a window lets it run flat out when nobody minds

Two patterns cover most sites. Scripted jobs get the flag, because it documents itself: anyone reading the script sees the limit. Everything else gets enforced where you own the control — the account on your server or a policy on the host you administer. When jobs run from an automation tool such as Sysax FTP Automation, they all originate from one Windows machine. So a single host policy there covers every scheduled transfer it runs, whichever protocol each uses.

The Honest Tradeoffs

Throttling is simple, and its problems are simple too. They are worth knowing before you promise anyone a result.

A static limit wastes idle capacity. A cap of 30 Mbit/s is right at two in the afternoon and absurd at two in the morning, when the other 20 Mbit/s sits unused. If a throttled job also runs overnight, give it two profiles (a daytime flag and a night-time one, chosen by the scheduler). Or move that job into an off-peak window and drop the throttle. The article on off-peak scheduling covers how. Network shaping avoids this problem because it only bites when the link is actually contended, which is the strongest argument for it.

Client-side limits are voluntary. A flag in a script is obeyed until someone edits the script, copies the command without it, or uses a different tool. A per-account server limit or a host policy survives all of those. Use the flag for convenience and something enforced for anything that matters.

Per-connection limits are multiplied by parallelism. Covered above, and easy to forget when the client is a partner who has just discovered their tool's "simultaneous transfers" setting. The fairness problems this creates — one partner starving the rest — are the subject of fairness between flows.

A slower job is a longer job. The 30 GB backup that took eighty minutes now takes over two hours. If other jobs wait behind it, the throttle can push the chain past its deadline. Check the window arithmetic before you slow anything that has successors.

Throttles are in bytes; links are in bits; both drift. The tool counts payload bytes; the link carries payload plus packet headers, plus encryption overhead for SFTP and FTPS. A 3.75 MB/s throttle produces a little more than 30 Mbit/s on the wire. That is a few percent, not a factor to worry about. But it is why a cap set at exactly the link speed still saturates the link. Set the cap at sixty to seventy percent of the link, not ninety-five.

The limit is only as good as your measurement. Follow every throttle with a check. Read the interface counters or the router graph while the throttled job runs. Confirm the rate is what you think and that latency for other users has come down. Measuring transfer impact shows how to make that routine.

The Version to Tell a Colleague

A throttle is a ceiling on a transfer's sending rate, built on a token bucket that allows a short burst and then a flat average. Every tool has one. There is --bwlimit in rsync, --limit-rate in curl and wget, and -l in scp (kilobits). There is net:limit-rate in lftp and /IPG in robocopy. Servers can cap per connection, per account, or globally, and only the per-account kind survives a client that opens several connections. When neither has a setting, a Windows QoS policy or Linux tc caps a process, a port, or an interface. Put the limit where you own the control, and set it at sixty to seventy percent of the link. Remember it wastes capacity at night, and measure the result.

From here, read network-level shaping and QoS for the throttle that only bites when the link is busy. Read off-peak scheduling for the option that needs no throttle at all.

Frequently Asked Questions

Is rsync's --bwlimit in kilobits or kilobytes?
Kibibytes per second (1024 bytes) when you give a bare number, so --bwlimit=3600 is about 3.7 MB/s, roughly 30 Mbit/s. You can add a suffix such as m for megabytes. scp's -l option is the one that uses kilobits.
Why does my throttled transfer start fast and then slow down?
That is the token bucket at work. The bucket fills while the tool is idle, so the first few seconds can run at full speed until the saved-up tokens are spent. After that the transfer settles at the configured average. It is normal and does not mean the limit is broken.
Can I limit the speed of an SFTP server built on OpenSSH?
Not inside OpenSSH itself; it has no bandwidth setting. Apply the limit at the operating system instead, with tc on Linux or a QoS policy on Windows. Or ask the network team to shape port 22 traffic at the edge. Clients can also limit themselves, but you cannot rely on that.
My server has a per-connection limit. Is that enough?
Only if you also cap the number of connections per account. A client that opens eight connections gets eight times the per-connection limit. Test it by opening several connections from one account and watching the total rate.
What percentage of the link should a daytime throttle allow?
Sixty to seventy percent is a sensible start. It leaves headroom for voice, remote desktop, and web traffic. It absorbs the packet and encryption overhead that the tool's byte count does not include. Measure latency for other users while the job runs and adjust.

From the Sysax team: we build secure file transfer software for Windows. Sysax Multi Server is an FTP, FTPS, SFTP, and HTTPS server. Sysax FTP Automation handles scheduled, scripted transfers. Free trials are on the download page.