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.

cmd
timeout /?

Output:

vbnet
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

cmd
timeout /T <seconds> [/NOBREAK]

Output: (countdown in console)

Essential options

SwitchMeaning
/T <seconds>Number of seconds to wait; range -1 to 99999
/T -1Wait indefinitely until a key is pressed (like pause but consistent)
/NOBREAKIgnore all keypresses — wait the full duration regardless
>NULSuppress the countdown display (silent pause)

Basic pause

timeout /T 5 counts down five seconds and then returns. Pressing any key exits immediately.

cmd
timeout /T 5

Output:

vbnet
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.

cmd
timeout /T 30 /NOBREAK

Output:

arduino
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.

cmd
timeout /T 10 /NOBREAK >NUL

Output:

css
(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.

cmd
echo Deployment complete. Review the log above.
timeout /T -1 >NUL

Output:

bash
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.

cmd
sc start MyService
timeout /T 10 /NOBREAK >NUL
sc query MyService | findstr STATE

Output:

markdown
        STATE              : 4  RUNNING

Common pitfalls

  1. /T is required — the number alone doesn't worktimeout 5 is invalid; always write timeout /T 5.
  2. Keypress bypass in interactive sessions — without /NOBREAK, an operator pressing any key during an automated run short-circuits the wait; use /NOBREAK for all unattended scripts.
  3. CTRL+C always exits regardless of /NOBREAK — there is no way to make timeout immune to CTRL+C; scripts that must not be interrupted should use a scheduled task or service instead.
  4. Max 99999 seconds (~27.7 hours) — for longer waits, loop timeout calls or use a scheduled task.
  5. Not available on XP/2003 — on older systems, use ping -n <n> 127.0.0.1 >NUL as the workaround; on Vista+ always prefer timeout.

Real-world recipes

Countdown before automatic reboot

cmd
@echo off
echo System will reboot in 60 seconds. Press CTRL+C to cancel.
timeout /T 60
shutdown /r /t 0

Output:

vbnet
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

cmd
@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:

css
Waiting for Print Spooler to stop...
Print Spooler restarted.

Poll a condition with repeated short waits

cmd
@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:

rust
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.

CommandWaitsInterruptibleAvailable sinceExit codes
timeout /T NN secondsAny key (unless /NOBREAK); always Ctrl+CVista0 normal; 1 if Ctrl+C
timeout /T -1IndefinitelyAny keyVista0 normal
pauseIndefinitelyAny keyEvery WindowsAlways 0
ping -n N 127.0.0.1 >NULAbout N-1 secondsOnly Ctrl+CEvery Windows0
choice /T N /D y /N >NULN secondsAny of the choice keys; default selected at endVista (built-in), earlier as Resource Kit1-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.

cmd
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.

cmd
rem Approximate 5-second sleep on XP / 2003
ping -n 6 127.0.0.1 >NUL

Output: (silent 5-second wait)

cmd
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
# PowerShell — millisecond precision
Start-Sleep -Milliseconds 250

Output: (250 ms wait)

cmd
rem Call PowerShell inline from a .bat script for a 500ms wait
powershell -NoProfile -Command "Start-Sleep -Milliseconds 500"

Output: (500 ms wait)

vb
' 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.

powershell
Start-Sleep -Seconds 5

Output: (5-second wait)

powershell
Start-Sleep -Milliseconds 250

Output: (250 ms wait)

powershell
# Shorthand — positional parameter is -Seconds
Start-Sleep 3

Output: (3-second wait)

Featuretimeout (cmd)Start-Sleep (PowerShell)
GranularitySecondsMilliseconds
Countdown shownYesNo
Interruptible by keypressYes (unless /NOBREAK)No
Interruptible by Ctrl+CYesYes
Max value99999 s2 147 483 647 ms
Default unitSecondsSeconds

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.

powershell
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:

code
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.

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:

vbnet
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.

cmd
timeout /T 5
echo Exit code: %errorlevel%

Output:

vbnet
Waiting for 5 seconds, press a key to continue ...
Exit code: 0
cmd
rem Missing /T — invalid syntax returns non-zero
timeout 5
echo Exit code: %errorlevel%

Output:

vbnet
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.

cmd
@echo off
echo Pretending to be uninterruptible...
timeout /T 60 /NOBREAK
echo This line runs only if Ctrl+C was NOT pressed.

Output:

css
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.

vbnet
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.

cmd
rem Robust pause for scheduled tasks
ping -n 6 127.0.0.1 >NUL

Output: (silent 5-second wait, works even with no console)

cmd
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.

cmd
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:

code
Done waiting 50 hours.
cmd
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:

vbnet
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.

cmd
@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:

css
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:

cmd
choice /T 5 /D R /N /C YNR /M "Yes / No / Retry (auto-R): "

Output:

arduino
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:

cmd
@echo off
if "%FAST_TEST%"=="1" (
    echo [test mode] skipping 60s wait
) else (
    timeout /T 60 /NOBREAK >NUL
)
echo Continuing...

Output (FAST_TEST=1):

bash
[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.

cmd
@echo off
set START=%TIME%
timeout /T 5 /NOBREAK >NUL
set END=%TIME%
echo Start: %START%
echo End:   %END%

Output:

makefile
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.

cmd
timeout /T 0

Output:

vbnet
Waiting for 0 seconds, press a key to continue ...

(returns immediately)

cmd
timeout /T -5

Output:

python
ERROR: Input value out of valid range.
Allowed range: -1 to 99999
Type "TIMEOUT /?" for usage.

Common pitfalls (continued)

  1. timeout fails when stdin is redirected — piping anything into timeout (echo y | timeout /T 5) returns "Input redirection is not supported" because timeout reads stdin for the keypress detector; if you must run under redirected stdin, use ping -n or Start-Sleep.
  2. /NOBREAK does not protect against Ctrl+C — only ordinary keypresses are ignored; signal traps still fire. Use cmd /c wrapping or PowerShell [Console]::TreatControlCAsInput = $true for true uninterruptible waits.
  3. Sleep mode pauses timeout real-time accounting — a 10-minute timeout started 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.
  4. PowerShell sleep alias is Start-Sleep, not timeout — calling sleep 5 in PowerShell waits 5 seconds via Start-Sleep; the same command in cmd is "not recognized".
  5. timeout may behave differently in remote PSSession — running cmd's timeout over PowerShell remoting can fail because the remote session lacks an interactive console; prefer Start-Sleep in 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.

cmd
@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:

csharp
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.

cmd
@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:

sql
 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:

cmd
@echo off
echo Snapshot in 10 seconds — press any key to skip ahead.
timeout /T 10
echo Taking snapshot...

Output:

vbnet
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.

powershell
$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.

cmd
@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:

arduino
Waiting before reboot...
Waiting for 30 seconds, press CTRL+C to quit ...

See also

Sources