cheat sheet
timeout
Pause a batch script for a specified number of seconds with an optional keypress bypass — a reliable replacement for the ping-delay idiom and a safer alternative to sleep in Windows CMD scripts.
timeout — Pause Script Execution
What it is
timeout is a built-in Windows command that pauses execution for a given number of seconds, counting down visibly in the console. It is the clean replacement for the old ping -n <n> 127.0.0.1 >NUL sleep hack used in older batch scripts. By default a keypress cancels the wait; adding /NOBREAK forces the full wait even if the user presses keys. Use timeout in deployment scripts to pause between steps, give services time to start, or display a countdown before an automatic action (like a reboot prompt). The PowerShell equivalent is Start-Sleep.
Availability
timeout ships as C:\Windows\System32\timeout.exe on Windows Vista and later.
timeout /?
Output:
TIMEOUT [/T] timeout [/NOBREAK]
Description:
This utility accepts a timeout parameter to wait for the specified
time period (in seconds) or until any key is pressed. It also
accepts a parameter to ignore key presses.
Parameter List:
/T timeout Specifies the number of seconds to wait.
Valid range is -1 to 99999 seconds.
/NOBREAK Ignore key presses and wait the specified time.
/? Displays this help message.
Syntax
timeout /T <seconds> [/NOBREAK]
Output: (countdown in console)
Essential options
| Switch | Meaning |
|---|---|
/T <seconds> | Number of seconds to wait; range -1 to 99999 |
/T -1 | Wait indefinitely until a key is pressed (like pause but consistent) |
/NOBREAK | Ignore all keypresses — wait the full duration regardless |
>NUL | Suppress the countdown display (silent pause) |
Basic pause
timeout /T 5 counts down five seconds and then returns. Pressing any key exits immediately.
timeout /T 5
Output:
Waiting for 5 seconds, press a key to continue ...
Forcing the full wait
/NOBREAK prevents any keypress from interrupting the countdown. Use this in unattended scripts where accidental keystrokes must not short-circuit a wait.
timeout /T 30 /NOBREAK
Output:
Waiting for 30 seconds, press CTRL+C to quit ...
Silent pause
Redirecting stdout to NUL suppresses the countdown message — useful in log-producing scripts where you want a clean output stream.
timeout /T 10 /NOBREAK >NUL
Output:
(none — waits silently)
Indefinite wait for keypress
/T -1 makes timeout wait indefinitely until the user presses any key. This is a cleaner alternative to pause when you need the exact same behavior but in a context where pause is unavailable or its hard-coded "Press any key to continue" message is undesirable.
echo Deployment complete. Review the log above.
timeout /T -1 >NUL
Output:
Deployment complete. Review the log above.
Using timeout to give a service time to start
A common pattern in deployment scripts is to start a service and then wait a few seconds before the next step so the service has time to initialize before dependent operations run.
sc start MyService
timeout /T 10 /NOBREAK >NUL
sc query MyService | findstr STATE
Output:
STATE : 4 RUNNING
Common pitfalls
/Tis required — the number alone doesn't work —timeout 5is invalid; always writetimeout /T 5.- Keypress bypass in interactive sessions — without
/NOBREAK, an operator pressing any key during an automated run short-circuits the wait; use/NOBREAKfor all unattended scripts. CTRL+Calways exits regardless of/NOBREAK— there is no way to maketimeoutimmune toCTRL+C; scripts that must not be interrupted should use a scheduled task or service instead.- Max 99999 seconds (~27.7 hours) — for longer waits, loop
timeoutcalls or use a scheduled task. - Not available on XP/2003 — on older systems, use
ping -n <n> 127.0.0.1 >NULas the workaround; on Vista+ always prefertimeout.
Real-world recipes
Countdown before automatic reboot
@echo off
echo System will reboot in 60 seconds. Press CTRL+C to cancel.
timeout /T 60
shutdown /r /t 0
Output:
System will reboot in 60 seconds. Press CTRL+C to cancel.
Waiting for 60 seconds, press a key to continue ...
Wait between service restarts in a script
@echo off
sc stop Spooler
echo Waiting for Print Spooler to stop...
timeout /T 5 /NOBREAK >NUL
sc start Spooler
echo Print Spooler restarted.
Output:
Waiting for Print Spooler to stop...
Print Spooler restarted.
Poll a condition with repeated short waits
@echo off
:wait_loop
sc query MyService | findstr "RUNNING" >NUL 2>&1
if %errorlevel%==0 (
echo MyService is running.
goto :done
)
echo Waiting for MyService...
timeout /T 3 /NOBREAK >NUL
goto wait_loop
:done
Output:
Waiting for MyService...
Waiting for MyService...
MyService is running.
timeout vs pause vs ping -n vs choice
cmd.exe has historically offered four ways to introduce a delay; each has different semantics. timeout is the modern, intentional sleep; pause waits for any key without a fixed duration; ping -n is the pre-Vista workaround; choice /T adds a default response after the delay. Picking the right one matters because they differ in interruptibility, exit-code behaviour, and accuracy.
| Command | Waits | Interruptible | Available since | Exit codes |
|---|---|---|---|---|
timeout /T N | N seconds | Any key (unless /NOBREAK); always Ctrl+C | Vista | 0 normal; 1 if Ctrl+C |
timeout /T -1 | Indefinitely | Any key | Vista | 0 normal |
pause | Indefinitely | Any key | Every Windows | Always 0 |
ping -n N 127.0.0.1 >NUL | About N-1 seconds | Only Ctrl+C | Every Windows | 0 |
choice /T N /D y /N >NUL | N seconds | Any of the choice keys; default selected at end | Vista (built-in), earlier as Resource Kit | 1-N depending on key |
The ping idiom waits N-1 seconds because the first ping is sent immediately and the last reply needs no wait after it. That subtle off-by-one is why timeout exists.
rem 5-second delay using each technique
timeout /T 5 /NOBREAK >NUL
pause
ping -n 6 127.0.0.1 >NUL
choice /T 5 /D y /N >NUL
Output: (each pauses 5 seconds — pause waits for a keypress instead)
ping -n workaround on legacy systems
On Windows XP, Server 2003, and earlier, timeout.exe did not ship with the OS — it was available only via the Windows Server 2003 Resource Kit. The portable workaround is ping -n <N+1> 127.0.0.1 >NUL, which sends N+1 ICMP echoes to the loopback address with one-second intervals and silences the output. The delay is roughly N seconds because ping waits one second between echoes.
rem Approximate 5-second sleep on XP / 2003
ping -n 6 127.0.0.1 >NUL
Output: (silent 5-second wait)
rem 30-second wait on legacy systems
ping -n 31 127.0.0.1 >NUL
Output: (silent 30-second wait)
The advantage of ping over timeout even on modern systems: ping is completely uninterruptible by keypress — only Ctrl+C can break it. The disadvantage: precision is ~1 second, the timing depends on loopback latency (occasionally a packet is "lost" and ping waits longer for a reply), and the technique pollutes the command's exit code (ping returns 0 always but emits nothing to indicate sleep completion).
For ultra-precise sub-second waits where timeout is not granular enough, use PowerShell's Start-Sleep -Milliseconds, the WSH WScript.Sleep, or choice /T 1 (also one-second resolution).
Sub-second waits
timeout only accepts integer seconds. For finer control, fall through to PowerShell or WSH.
# PowerShell — millisecond precision
Start-Sleep -Milliseconds 250
Output: (250 ms wait)
rem Call PowerShell inline from a .bat script for a 500ms wait
powershell -NoProfile -Command "Start-Sleep -Milliseconds 500"
Output: (500 ms wait)
' One-line VBScript invoked from .bat — WScript.Sleep takes ms
echo WScript.Sleep 750 > sleep.vbs && cscript //nologo sleep.vbs && del sleep.vbs
Output: (750 ms wait)
Starting a PowerShell process for a single sleep is heavyweight — the process spin-up alone takes 150-400 ms on first run. For tight inner loops, batch a series of small waits into one PowerShell invocation or use a TIMER COM object via WSH.
PowerShell equivalent: Start-Sleep
Start-Sleep is the canonical PowerShell delay cmdlet. It takes either -Seconds (integer) or -Milliseconds (integer up to Int32.MaxValue, about 24 days). Unlike timeout, Start-Sleep cannot be interrupted by a keypress — only Ctrl+C breaks it. It does not display a countdown by default.
Start-Sleep -Seconds 5
Output: (5-second wait)
Start-Sleep -Milliseconds 250
Output: (250 ms wait)
# Shorthand — positional parameter is -Seconds
Start-Sleep 3
Output: (3-second wait)
| Feature | timeout (cmd) | Start-Sleep (PowerShell) |
|---|---|---|
| Granularity | Seconds | Milliseconds |
| Countdown shown | Yes | No |
| Interruptible by keypress | Yes (unless /NOBREAK) | No |
Interruptible by Ctrl+C | Yes | Yes |
| Max value | 99999 s | 2 147 483 647 ms |
| Default unit | Seconds | Seconds |
Showing a countdown in PowerShell
Start-Sleep is silent. To replicate the timeout countdown UI, loop in one-second increments with Write-Host -NoNewline and a carriage return.
function Show-Countdown {
param([int]$Seconds, [string]$Message = "Waiting")
for ($i = $Seconds; $i -gt 0; $i--) {
Write-Host "`r$Message $i seconds... " -NoNewline
Start-Sleep -Seconds 1
}
Write-Host "`r$Message complete. "
}
Show-Countdown -Seconds 5 -Message "Restarting in"
Output:
Restarting in 5 seconds...
Restarting in 4 seconds...
Restarting in 3 seconds...
Restarting in 2 seconds...
Restarting in 1 seconds...
Restarting in complete.
Cancelable wait with [Console]::KeyAvailable
Combine Start-Sleep with a keypress poll to get timeout-like cancellable behaviour in PowerShell.
function Wait-WithEscape {
param([int]$Seconds)
$deadline = (Get-Date).AddSeconds($Seconds)
while ((Get-Date) -lt $deadline) {
if ([Console]::KeyAvailable) {
$null = [Console]::ReadKey($true)
Write-Host "Skipped."
return
}
Start-Sleep -Milliseconds 100
}
}
Write-Host "Press any key to skip, otherwise wait 10 seconds..."
Wait-WithEscape -Seconds 10
Output:
Press any key to skip, otherwise wait 10 seconds...
timeout exit codes
timeout returns 0 when the wait completes (whether naturally or via keypress) and a non-zero code only on argument errors or when the operating system terminates it. This is convenient because you cannot tell from the exit code whether the user pressed a key — for scripts that need to branch on "did the user interrupt?", use choice instead.
timeout /T 5
echo Exit code: %errorlevel%
Output:
Waiting for 5 seconds, press a key to continue ...
Exit code: 0
rem Missing /T — invalid syntax returns non-zero
timeout 5
echo Exit code: %errorlevel%
Output:
ERROR: Invalid syntax. '/T' option is not allowed in the current operating mode.
Type "TIMEOUT /?" for usage.
Exit code: 1
Interaction with Ctrl+C
Ctrl+C always terminates timeout — /NOBREAK only disables ordinary keypresses, not the interrupt. When you write a batch script with timeout /NOBREAK followed by destructive operations, a user hitting Ctrl+C exits the entire script (unless trapped with cmd /c or PowerShell-wrapped). For waits that must absolutely complete, use a scheduled task triggered later instead of a foreground timeout.
@echo off
echo Pretending to be uninterruptible...
timeout /T 60 /NOBREAK
echo This line runs only if Ctrl+C was NOT pressed.
Output:
Pretending to be uninterruptible...
Waiting for 60 seconds, press CTRL+C to quit ...
This line runs only if Ctrl+C was NOT pressed.
If the user presses Ctrl+C, cmd.exe typically prompts "Terminate batch job (Y/N)?" and the next line never runs.
timeout in non-interactive contexts
timeout requires a console with an input handle. When cmd.exe is launched detached (no console attached, e.g. via Task Scheduler with hidden window, CreateProcess with DETACHED_PROCESS, or a Windows Service), timeout errors out immediately because it cannot read stdin to check for keypresses.
ERROR: Input redirection is not supported, exiting the process immediately.
The workaround is /NOBREAK >NUL <NUL or — more reliably — replacing timeout with ping -n or PowerShell Start-Sleep in scheduled / service scripts.
rem Robust pause for scheduled tasks
ping -n 6 127.0.0.1 >NUL
Output: (silent 5-second wait, works even with no console)
rem Or PowerShell — also console-independent
powershell -NoProfile -Command "Start-Sleep 5"
Output: (silent 5-second wait)
Long waits and the 99999-second cap
timeout rejects values above 99999 seconds (about 27 hours, 46 minutes, 39 seconds). For longer foreground waits, loop multiple timeout calls or — better — switch to a scheduled task triggered at the desired future time.
rem Wait approximately 50 hours by chaining two timeouts
timeout /T 99999 /NOBREAK >NUL
timeout /T 80001 /NOBREAK >NUL
echo Done waiting 50 hours.
Output:
Done waiting 50 hours.
rem Better: schedule a task and exit immediately
schtasks /Create /TN "Resume50h" /SC ONCE /ST 14:30 /SD 05/27/2026 /TR "C:\Scripts\resume.bat" /F
Output:
SUCCESS: The scheduled task "Resume50h" has successfully been created.
For 1-2 hour waits, timeout is fine; beyond that, scheduling is more reliable because a 50-hour foreground process is at the mercy of console-window closes, user logoff, and screen lock.
timeout and set /P — interactive vs timed input
There is no built-in way to combine set /P (read input) with a timeout — the prompt waits forever. The common workaround uses choice /T <seconds> /D <default> which auto-selects a default key after the timeout expires.
@echo off
choice /T 10 /D Y /N /M "Continue? Y/N (auto-Y in 10s): "
if errorlevel 2 (
echo Aborted.
) else (
echo Continuing...
)
Output:
Continue? Y/N (auto-Y in 10s):
Continuing...
choice returns 1 for the first option (Y here, default), 2 for the second (N). It supports any character set via /C:
choice /T 5 /D R /N /C YNR /M "Yes / No / Retry (auto-R): "
Output:
Yes / No / Retry (auto-R):
After 5 seconds with no input, R is auto-selected and errorlevel is 3.
Bypassing timeout for testing
When writing batch scripts that contain long timeout calls, set a FAST_TEST=1 environment variable and skip the waits during development:
@echo off
if "%FAST_TEST%"=="1" (
echo [test mode] skipping 60s wait
) else (
timeout /T 60 /NOBREAK >NUL
)
echo Continuing...
Output (FAST_TEST=1):
[test mode] skipping 60s wait
Continuing...
timeout accuracy and the Windows tick
timeout is precise to about 50 ms on modern Windows — the system tick interval. It is not real-time and will be delayed by heavy CPU load, paging activity, or hibernation/sleep cycles in the middle of a wait. For benchmarks and time-sensitive code, do not rely on timeout for exact timing; instead capture the actual elapsed time with %TIME% or PowerShell Measure-Command.
@echo off
set START=%TIME%
timeout /T 5 /NOBREAK >NUL
set END=%TIME%
echo Start: %START%
echo End: %END%
Output:
Start: 14:22:05.31
End: 14:22:10.34
The difference is typically a few tens of milliseconds over the requested duration. After hibernation in the middle of a wait, timeout resumes counting from where it left off — it does not account for wall-clock time spent suspended. Long waits across sleep cycles will under-count significantly.
Reading help and edge cases
timeout /? prints the usage. The valid range is -1 to 99999. Zero is allowed but useless — it returns instantly. Negative numbers other than -1 are rejected.
timeout /T 0
Output:
Waiting for 0 seconds, press a key to continue ...
(returns immediately)
timeout /T -5
Output:
ERROR: Input value out of valid range.
Allowed range: -1 to 99999
Type "TIMEOUT /?" for usage.
Common pitfalls (continued)
timeoutfails when stdin is redirected — piping anything intotimeout(echo y | timeout /T 5) returns "Input redirection is not supported" becausetimeoutreads stdin for the keypress detector; if you must run under redirected stdin, useping -norStart-Sleep./NOBREAKdoes not protect againstCtrl+C— only ordinary keypresses are ignored; signal traps still fire. Usecmd /cwrapping or PowerShell[Console]::TreatControlCAsInput = $truefor true uninterruptible waits.- Sleep mode pauses
timeoutreal-time accounting — a 10-minutetimeoutstarted before the laptop sleeps for 30 minutes will still wait the full 10 minutes of running time after resume; it does not advance during S3/S4. - PowerShell
sleepalias isStart-Sleep, nottimeout— callingsleep 5in PowerShell waits 5 seconds viaStart-Sleep; the same command in cmd is "not recognized". timeoutmay behave differently in remote PSSession — running cmd'stimeoutover PowerShell remoting can fail because the remote session lacks an interactive console; preferStart-Sleepin remote scripts.
Real-world recipes (continued)
Retry-with-backoff for transient HTTP errors
A common deployment pattern: retry an operation a few times with increasing delays before giving up.
@echo off
setlocal enabledelayedexpansion
set ATTEMPT=0
set MAX=5
set DELAY=2
:retry
set /A ATTEMPT+=1
curl -sf https://example.com/health
if !errorlevel! == 0 (
echo Health check passed on attempt !ATTEMPT!.
goto :ok
)
if !ATTEMPT! geq !MAX! (
echo Failed after !MAX! attempts.
exit /b 1
)
echo Attempt !ATTEMPT! failed. Waiting !DELAY!s...
timeout /T !DELAY! /NOBREAK >NUL
set /A DELAY=DELAY*2
goto retry
:ok
Output:
Attempt 1 failed. Waiting 2s...
Attempt 2 failed. Waiting 4s...
Health check passed on attempt 3.
Visible countdown with audible bell at zero
A reboot-warning script that uses cls and timeout /T 1 in a loop to redraw a large countdown each second; rings the bell at zero.
@echo off
for /L %%i in (10,-1,1) do (
cls
echo.
echo System reboot in %%i seconds.
echo Press Ctrl+C to cancel.
timeout /T 1 /NOBREAK >NUL
)
cls
echo ^G
echo Rebooting now...
shutdown /r /t 0
Output:
System reboot in 10 seconds.
Press Ctrl+C to cancel.
... (counts down each second)
Rebooting now...
(The ^G is a literal BEL character — produce it with Alt+007 on the numeric keypad while editing.)
Hybrid timeout + key-skip prompt
A deployment script that offers the operator a chance to cancel during the wait, with /NOBREAK flipped intentionally to enable interrupt:
@echo off
echo Snapshot in 10 seconds — press any key to skip ahead.
timeout /T 10
echo Taking snapshot...
Output:
Snapshot in 10 seconds — press any key to skip ahead.
Waiting for 10 seconds, press a key to continue ...
Taking snapshot...
PowerShell parallel waits
When a script needs many independent waits — for example, restarting several services with staggered timing — PowerShell jobs are cleaner than chained timeout calls.
$services = "Spooler","BITS","wuauserv"
$jobs = foreach ($svc in $services) {
Start-Job -ArgumentList $svc -ScriptBlock {
param($s)
Stop-Service $s -Force
Start-Sleep -Seconds 5
Start-Service $s
}
}
$jobs | Wait-Job | Receive-Job
Output: (all three services restart in parallel, each with its own 5-second gap)
Polite shutdown notification window
Pop a message via msg.exe, wait 30 seconds (with countdown visible to the operator running the script), then trigger shutdown.
@echo off
msg * /TIME:30 "System rebooting for maintenance in 30 seconds."
echo Waiting before reboot...
timeout /T 30 /NOBREAK
shutdown /r /t 0 /c "Scheduled maintenance"
Output:
Waiting before reboot...
Waiting for 30 seconds, press CTRL+C to quit ...
See also
- PowerShell Essentials —
Start-Sleep,Wait-Job,Start-ThreadJob, and timing operators. - shutdown — Restart, Power Off, and Hibernate — pairs naturally with
timeoutfor delayed reboots. - schtasks — Task Scheduler from the CLI — long delays should usually become a scheduled task instead of a foreground
timeout. - sc — Service Controller — service start/stop sequences typically use
timeoutbetween commands. - echo — Output Text and Control Command Echo — paired with
timeoutfor the standard "doing X then waiting" pattern.
Sources
- Start-Sleep — Microsoft Learn (PowerShell 7.5) — PowerShell equivalent;
-Duration [timespan]added in 7.3 for readable time spans. - Start-Sleep — PowerShell Docs main branch — current 7.6 reference covering millisecond precision and timespan input.
- PowerShell Sleep — LazyAdmin — practical comparison of
timeout,Start-Sleep, andpausepatterns. - Mastering PowerShell Sleep — Netwrix — cancellable waits and
[Console]::KeyAvailablepatterns.