Call of Duty rcon: commands, wire protocol and flood protection

Updated 2026-07-25

Remote console is how you administer a running Call of Duty server without restarting it. It is a single UDP request/response with the password in cleartext, which tells you most of what you need to know about how much to trust it.

The cvar name differs per game

Game Cvar
Call of Duty 1 rconpassword
Call of Duty: United Offensive rconpassword
Call of Duty 2 rcon_password
Call of Duty 4 rcon_password
Call of Duty: World at War rcon_password

Setting the wrong one leaves rcon disabled with no error at startup. A config copied from a CoD1 server to a CoD2 server is the most common cause of "rcon does not work".

Using it from the game console

Connect to the server, open the console and set the password once:

/rconpassword mysecret          // CoD1 / UO
/rcon_password mysecret         // CoD2 / CoD4 / WaW
/rcon status
/rcon map mp_carentan

Useful commands

Command Effect
status Player list with slot number, score, ping, GUID, IP
serverinfo Current cvar snapshot
map <name> Change map immediately
map_rotate Advance to the next entry in sv_mapRotation
map_restart Restart current map, keeps scores
fast_restart Restart the round without reloading the map
kick <name> Kick by name
clientkick <slot> Kick by slot number from status
banclient <slot> Ban by slot
tempbanclient <slot> Temporary ban
say <text> Server message in chat
set <cvar> <value> Change any cvar
<cvar> Read a cvar back

Reading a cvar back returns the current and default value:

"sv_maxclients" is:"20^7" default:"8^7"

That echo is the basis of the verification pattern below.

The wire protocol

Quake3-derived, so it is four 0xFF bytes followed by a plain-text command:

\xff\xff\xff\xffrcon <password> <command>

The reply is:

\xff\xff\xff\xffprint\n<output>

Which means you never need a client library:

import socket

def rcon(host, port, password, command, timeout=2.0):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.settimeout(timeout)
    s.sendto(b'\xff\xff\xff\xffrcon %s %s' % (password.encode(), command.encode()),
             (host, port))
    out = b''
    try:
        while True:
            out += s.recv(8192)
    except socket.timeout:
        pass
    return out.decode('latin-1', 'replace').replace('\xff\xff\xff\xffprint\n', '')

print(rcon('127.0.0.1', 28960, 'mysecret', 'status'))

The same trick gives you a server query without rcon at all, which is how server browsers work:

printf '\xff\xff\xff\xffgetstatus' | nc -u -w2 YOUR.IP 28960 | head -c 400

If that returns configstrings, your server is reachable from the outside and any "not in the browser" problem is master-side. See server not in the browser.

Flood protection: the trap that eats automation

CoD applies sv_floodProtect to rcon. Two rcon commands within roughly 500 ms collapse, and the second one comes back as Bad rconpassword. or an empty reply.

That response is indistinguishable from a genuinely wrong password or a dropped UDP packet.

It gets worse: a set <cvar> <value> returns an empty reply even on success. So there is no way to distinguish a landed set from a lost one by looking at the response.

The consequences for anything scripted:

  • Space rcon commands at least 600 ms apart.
  • Treat an empty reply or Bad rconpassword as probably flood, and retry, rather than concluding your password is wrong.
  • Never trust a one-shot set.

Set-and-verify

The reliable pattern is to set, read back, compare, and retry with jitter:

import time, random

def set_cvar_verified(host, port, password, cvar, value, attempts=5):
    for i in range(attempts):
        rcon(host, port, password, f'set {cvar} "{value}"')
        time.sleep(0.7)
        echo = rcon(host, port, password, cvar)
        if f'"{cvar}" is:"{value}' in echo:
            return True
        time.sleep(1 + random.random() * 2)
    return False

This is not theoretical. A scheduled job that flipped a gameplay cvar once, had the packet dropped by flood protection, and never verified it, left a public server stuck in the wrong mode for hours. One read-back would have caught it.

Log noise you can ignore

Two lines appear constantly in server logs and mean nothing is wrong:

Rcon from <ip>:<negative port>
cmdCount > MAX_PACKET_USERCMDS

The first is NAT artefacts in the port field, the second is a client sending user commands faster than the server samples them. Filter both out before reading logs:

grep -v 'cmdCount\|MAX_PACKET\|Rcon from' server.log | tail -50

Security

The password travels in cleartext in a UDP datagram, and there is no rate limit on authentication attempts beyond flood protection. Therefore:

  • Use a long random password, not a word.
  • Use a different password per server.
  • Do not reuse it anywhere else.
  • Where possible, firewall the game port to accept rcon only from your admin addresses.

Tools

The CoD RCON Tool on war24.net is a Windows GUI client for the classic titles. For anything scripted, the twenty lines of Python above are usually a better fit than a GUI.

For a persistent admin layer with bans, roles and chat commands, look at B3 (BigBrotherBot), which parses the server log and drives rcon.

Frequently asked

Why does rcon return 'Bad rconpassword' when the password is correct?

Flood protection. Two rcon commands within about 500 ms collapse and the second returns Bad rconpassword or an empty reply, which looks identical to an authentication failure. Space commands at least 600 ms apart and retry.

Is it rconpassword or rcon_password?

rconpassword as one word on Call of Duty 1 and United Offensive. rcon_password with an underscore on Call of Duty 2, Call of Duty 4 and World at War.

How can I tell whether an rcon 'set' command actually applied?

You cannot from the response, because set returns an empty reply on success. Read the cvar back afterwards; the server echoes \"cvar\" is:\"value\" default:\"...\" and you compare against that.