Home › Topics › Resume & Restart › Support Compared

Resume Support Compared: Clients, Servers, and Settings

"Does it support resume?" is the wrong question, because it has no single answer. A client can support resume and still restart from zero because a checkbox was left on its default. A server can support resume in general and refuse it for one account, one folder, or one transfer mode. A proxy in the middle can strip the one header that makes it work. Resume is a property of a whole path: client settings, client capability, network path, server capability, server permissions. It takes only one of those to fail for the whole thing to fall back to starting over.

This article is the checklist for that path. It compares support by class of tool rather than by brand: graphical clients, command-line clients, libraries, and servers for each protocol. Then it covers the settings on each that silently disable resume. It also covers the one danger that no setting fixes: resuming onto a file whose source has changed. It ends with a test you can run in ten minutes to find out whether your resume actually resumes.

It is part of our Resume & Restart series and assumes you have seen how resume works in each protocol: the FTP REST marker, SFTP offsets, HTTP ranges, and rsync's partial files.

Resume Is a Property of the Pair

Think of a resumed transfer as passing through five gates. The client must be configured to try. The client must know how, for this protocol. The network path must carry the request unchanged. The server must implement the mechanism. And the server must permit it for this account and folder. The diagram shows the five gates in order; every "resume didn't work" report you will ever get is one of them closed.

Five gates a resumed transfer must pass: client setting, client capability, network path, server capability, and server permission. Any closed gate makes the transfer restart from zero.

The word to notice is "silently". Most tools do not report "resume was refused, restarting". They restart. The only evidence is a byte counter that starts at zero or a transfer that takes as long as the first attempt did. That is why the test at the end of this article matters more than any documentation claim.

Clients, by Class

Graphical clients

Almost every graphical FTP, SFTP, and multi-protocol client can resume. The question is what it does by default when the destination file already exists. Look for a setting with a name like "default action when file exists" or "overwrite policy". The usual choices are overwrite, resume, rename, skip, and ask. "Ask" is fine for a person at a keyboard and useless for a queue left running overnight. Some clients add a conditional option, "resume if the existing file is smaller, otherwise overwrite", which is the sensible default for downloads.

Three other settings decide whether that choice actually works. The transfer type must be binary, not "auto". Auto mode picks ASCII for files with text-like extensions, and ASCII transfers cannot be resumed. A temporary filename during transfer option, if enabled, gives the partial on disk a different name. That differs from the name the client will look for when resuming. Some clients handle their own temp names correctly and some do not. And a delete incomplete files or "remove failed downloads" option, which exists in several clients, guarantees there is never a partial to resume from. Graphical clients that resume well tend to gray out the Resume choice when the server's FEAT reply lacks REST STREAM. That is a useful hint that the server, not the client, is the closed gate.

Command-line clients

Command-line tools are explicit: resume happens when you pass the flag, and only then. The table lists the ones you will meet.

Tool Resume download Resume upload Notes
curl -C - (HTTP, FTP, SFTP) -C - with -T on FTP/SFTP Refuses to glue a full 200 response onto a partial; exit code 33
wget -c (HTTP, FTP) Not an upload tool Refuses to overwrite a partial when the server ignores ranges
OpenSSH sftp reget, get -a reput, put -a Refuses if the partial is larger than the source; does not check its contents
scp None None Use sftp or rsync for anything large
lftp get -c, pget -c, mirror -c put -c, mirror -R -c Reconnects and resumes automatically; picks the right mechanism per protocol
rsync --partial --partial-dir Same flags; --append-verify for grow-only files Without --partial the interrupted file is deleted
Built-in Windows ftp.exe None None No REST support and active mode only; a login tester, not a transfer tool

Two of these deserve a second look. curl resumes uploads too: curl -C - -T localfile ftp://host/path/ asks the server for the remote size and sends from there. And rsync is the odd one out. Its resume is not a flag on the retry but a flag on the first attempt. If the interrupted run was not started with --partial, there is nothing left to resume. Our command-line one-liners cookbook has the full invocations.

Libraries and scripting

Libraries give you the mechanism and none of the policy. Python's standard ftplib, for example, accepts a rest= argument on retrbinary and storbinary that sends the REST command. Deciding the offset, opening the local file in append mode, and checking the reply are your job. Paramiko's SFTP file objects have seek, as shown in the per-protocol article. HTTP client libraries generally let you set any request header. So resume means adding Range yourself. Then check that the status was 206 and not 200 before writing a single byte. Frameworks with a built-in FTP class usually expose a content-offset property that does the same thing as REST.

The recurring mistake in scripted resume is trusting the library to notice a refused resume. It will not. If the server ignores REST and sends the file from the start, retrbinary happily hands you the whole file. Your append-mode write then produces a file one and three-quarter times the right size. Every scripted resume needs three checks around it: the remote size before, the status or reply code during, and the final size and hash after. Our articles on Python FTP and FTPS and reliability inside applications show where those checks go.

Servers, by Protocol

FTP and FTPS servers

Ask the server directly. Connect with any client that shows the raw conversation and send FEAT:

> FEAT
< 211-Features:
<  MDTM
<  REST STREAM
<  SIZE
<  UTF8
< 211 End

REST STREAM means the server implements restart markers for ordinary stream-mode transfers. SIZE means clients can learn a remote file's size, which upload resume depends on. If either is missing, resume is off for everyone. If both are present, the remaining gate is per-account permission. Many FTP servers separate the right to create files from the right to overwrite or append to existing ones. A "drop box" account that can only create will fail a resumed upload with 550 Permission denied even though the first attempt worked. Some servers also let an administrator disable REST for uploads specifically. The reason is that this command lets a client overwrite the middle of a file. Check the server's own settings if REST before STOR is refused while REST before RETR works. A server product such as Sysax Multi Server serves FTP, FTPS, SFTP, and HTTPS. It exposes its per-account permissions and activity logging in its configuration interface. Whatever server you run, confirm behavior with the test at the end rather than the feature list.

SFTP servers

Because offsets are part of every SFTP request, an SFTP server that follows the protocol resumes without knowing it. The gates that remain are permission and storage. Resuming an upload means opening an existing remote file for writing without truncating it. A server configured for append-only or create-only upload folders may refuse. Servers that present something other than a local filesystem — object storage, a database, an archive — may accept writes only sequentially from offset zero. There is no FEAT to query in SFTP, so the test is the only way to know. The standard OpenSSH server and its internal SFTP subsystem resume fine; see SFTP server configuration for the folder and permission settings that interact with it.

HTTP and HTTPS servers

A HEAD request answers the question:

$ curl -sI https://files.example.com/nightly-backup.tar.gz
HTTP/1.1 200 OK
Content-Length: 1500000000
Accept-Ranges: bytes
ETag: "a1b2c3-59682f00"

Accept-Ranges: bytes says ranges are honored. Accept-Ranges: none, or no such header at all, means assume not. Static files served straight off disk by any mainstream web server support ranges. Downloads generated by application code usually do not unless the developer added it. And anything that passes through a caching proxy or content-delivery layer may lose the header on the way. The ETag, and the Last-Modified header that usually accompanies it, are what a careful client stores to detect a changed source later.

rsync

rsync needs nothing special on the far side, whether it runs over SSH or as a daemon, with one exception. The destination directory must be writable enough to hold the --partial-dir folder. A daemon module marked read-only is fine as a source and useless as a destination, resume or not. See rsync over SSH versus the daemon for the difference.

The Settings That Silently Turn Resume Off

Collected in one place, because in practice this table is the troubleshooting guide.

Setting Where it lives Why it kills resume Set it to
Transfer type = auto or ASCII Client ASCII offsets are undefined; a resumed text file is corrupt Binary, always
Existing-file action = overwrite or ask Client Overwrite discards the partial; ask hangs an unattended queue Resume, or resume-if-smaller
Delete incomplete files Client There is never a partial to resume from Off for resumable flows
Temporary name during transfer Client or server The partial has a different name from the one the resume looks for Keep it, but make sure the tool resumes onto its own temp name
No REST STREAM or SIZE in FEAT FTP server Server cannot restart, or client cannot learn the remote size Enable, or accept restart-only for that server
Create-only or append-denied account FTP or SFTP server Resumed upload is refused with 550 or a permission error Grant append/overwrite in the upload folder
Write-only upload folder (no listing) Server Client cannot SIZE or stat the partial, so cannot find the offset Allow size queries, or use a protocol that does not need them
Proxy or gateway in the path Network Strips Range, or does not forward REST to the real server Test through the proxy, not around it

The temporary-name row is worth a second look because it collides with a practice we recommend elsewhere. Writing to file.part and renaming to file on completion — the atomic rename pattern — is how you stop consumers from picking up half a file. It is fully compatible with resume as long as the resuming side looks for file.part, resumes onto it, and renames at the end. rsync's --partial-dir does exactly this. A client that writes file.part but looks for file when resuming will never find its partial.

The Modified-Source Danger

Every setting above can be fixed. This one cannot; it can only be detected. Suppose a nightly export is regenerated at 01:00 under the same name, orders-export.csv.gz. Last night's download was interrupted at 75%. Tonight the resume-capable client finds a partial, asks the server for the size, and requests bytes from the partial's end onward. The server obliges. The result is the first three-quarters of yesterday's export joined to the last quarter of today's. Its size matches today's file exactly. It decompresses with an error at best, or at worst produces a plausible-looking table of orders that never existed together.

No protocol checks for this. The defenses are all on your side:

  • Compare timestamps before resuming. If the source's modification time is newer than the partial's creation time, the partial is garbage. FTP's MDTM command, SFTP's file attributes, and HTTP's Last-Modified header all give you the source time.
  • Use the protocol's version check where one exists. In HTTP, send If-Range with the stored ETag. A changed file gets you a full 200 instead of a 206, and the tool starts over cleanly. In rsync, prefer --append-verify to --append, or better, plain --partial-dir, which checksums the blocks it reuses.
  • Never reuse names for regenerated files. A datestamp in the name — orders-export-20250314.csv.gz — means tonight's file can never be confused with last night's partial. Our datestamp formats article shows conventions that sort correctly.
  • Age out partials. A partial older than your flow's cycle — a day for a nightly job — should be deleted, not resumed.
  • Hash at the end regardless. The final defense, covered in verifying a resumed transfer.

Remember: resume trusts that the partial is the beginning of the file being sent. A file regenerated under the same name breaks that trust without any error, and the resulting file will have the right size. Unique names per run and a timestamp check before resuming are cheaper than any verification you can do afterwards.

Test Resume Before You Trust It

Ten minutes with a test file settles what the documentation cannot. The procedure below uses curl against an FTP server, but the shape is identical for any tool and protocol. Substitute your own client's commands.

# 1. Make a 200 MB test file of random bytes and record its hash
dd if=/dev/urandom of=resume-test.bin bs=1M count=200
sha256sum resume-test.bin > resume-test.sha256

# 2. Start the upload and kill it after 20 seconds (curl prompts for the password)
timeout 20 curl -sS -T resume-test.bin ftp://ftp.example.com/incoming/ --user batch
echo "exit code: $?"          # 124 means timeout killed it, as intended

# 3. Confirm a partial exists on the server and note its size
curl -sS --user batch ftp://ftp.example.com/incoming/ | grep resume-test.bin

# 4. Resume, watching the byte counter start from the partial size, not zero
curl -v -C - -T resume-test.bin ftp://ftp.example.com/incoming/ --user batch 2>&1 | grep -E "REST|350|APPE|STOR|226"

# 5. Download it back and compare hashes
curl -sS --user batch -o roundtrip.bin ftp://ftp.example.com/incoming/resume-test.bin
sha256sum roundtrip.bin
cat resume-test.sha256

Step 1 uses random data so that a wrong join cannot accidentally produce the right hash. Step 2's timeout kills the transfer part-way; the exit code 124 confirms it was the timeout and not an error. Step 3 proves a partial exists. If it does not, a setting on one side deleted it, and you have found your first closed gate. Step 4 is the heart of the test. In the verbose output you want to see REST followed by a 350 reply, or an APPE, and then 226. If you see STOR with no REST before it, the tool restarted. Step 5 is the proof: the two hashes must match exactly.

Then run the test three more times. Run it once as a download and once through any proxy or gateway that production traffic uses. Run it once after modifying the source between the kill and the resume. That shows what your tool does when the source changes. The last run should fail loudly; if it succeeds, you now know your flow needs the timestamp or name-based defenses above. Write the results down next to the flow's documentation, because "we tested resume on this path" is exactly the kind of fact that gets lost.

For unattended jobs, the same test tells you whether your automation's retry actually resumes. A scheduled job in a tool like Sysax FTP Automation can be pointed at a test folder and interrupted the same way. Its log can be read afterwards. The retry and error-handling settings decide that a retry happens. The test decides what the retry does with the partial.

The Version to Keep in Your Head

Resume works only when five gates are open. The client is set to try, and the client knows how. The path carries the request, the server implements it, and the account is allowed. Graphical clients hide the first gate in an "existing file" default. Command-line tools open it with a flag. Libraries open the second gate and leave every check to you. Servers advertise support in FEAT (FTP) or Accept-Ranges (HTTP). They need no advertisement for SFTP. They close the last gate with per-account append and overwrite permissions. None of them protects you from a source that changed between attempts, so name regenerated files uniquely and compare timestamps. And test, with random data and a deliberate kill, before any unattended job depends on it.

Next in the series: checkpointing in automated jobs moves from single files to whole runs, and a resume strategy for your flows turns these checks into a per-flow decision. If a large share of your flows involve very big files, the large-file strategies series covers the design side.

Frequently Asked Questions

How do I tell whether an FTP server supports resume?
Send the FEAT command and look for REST STREAM and SIZE in the reply. REST STREAM means the server accepts restart markers; SIZE means clients can learn a remote file's size, which upload resume needs. Both present means the server can; the account's permissions decide whether it may.
My client says it resumed, but the transfer took as long as the first attempt. Why?
The server most likely refused or ignored the resume request and sent the file from the start. The client did not report it. Check the raw log for a REST command followed by a 350 reply (FTP) or a 206 status (HTTP). If you see STOR or RETR without REST, or a 200 instead of 206, one of the gates in this article is closed.
Why does resuming an upload fail with 550 when the first upload worked?
The account can create files but not write to existing ones. Many servers separate create, overwrite, and append permissions, and a drop-box style account often has only the first. Ask the server administrator to allow append or overwrite in that folder, or accept that uploads to it are restart-only.
Is it safe to resume a file whose name is reused every night?
Only if you check the source's modification time against the partial first. If the source was regenerated after the partial was written, resuming joins two different files together and produces a corrupt result of the correct size. Datestamped file names avoid the problem entirely.
Does SFTP need a server-side setting to enable resume?
Normally no, because every SFTP read and write carries an offset. The things that can stop it are folder permissions that forbid writing to existing files, and servers whose storage is not a real filesystem. A quick reget test against a real file is the reliable check.

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.