JoinGG.cc
Features

RCON Explained: Remote Control Without SSH

RCON hands console commands to a live game server over TCP, in cleartext. Learn the packet format, the 4096-byte truncation trap, and how to lock the port down.

By SweetMask · · 19 min read

RCON is a small TCP protocol that lets an authenticated client send console commands to a running game server and read the output. It carries the password in cleartext on the first packet and has no encryption, so it belongs on localhost behind an SSH tunnel or a firewall allowlist, never open to the internet.

Published 3 October 2026 · JoinGG · Guides

If you have ever opened a server.cfg and seen a line reading rcon_password that you did not write and have never used, this article is for you. That line is the reason your host's web panel has a command box, why your Discord restart bot works, and why a scanner in another country is trying passwords against your box right now. It is also, on more than a few of the 1,588 Counter-Strike 1.6 servers currently visible on the CS 1.6 player and server statistics page, set to something like changeme.

RCON is worth understanding at the packet level because the protocol's design decisions leak straight into the failures you will actually hit: truncated output, a client that hangs, a password you cannot tell is wrong, and a security model that assumes a 1998 LAN.

What RCON is, and what it is not

RCON stands for remote console. It does exactly one thing: it hands a string to the game server's console command parser and hands you back whatever the console printed in response. That is the entire feature set. It is not a shell, it cannot read or write files, it cannot start a process that has died, and it has no concept of a user beyond a single shared password.

The reason it exists is mundane. A dedicated game server has an interactive console, and in 1999 you sat at the machine and typed into it. The moment servers moved to rented hardware, the console became unreachable. Today it is worse: under systemd, Docker or a panel, standard input belongs to the supervisor, not to you. RCON reattaches that console over the network so the server can be driven without touching the process.

Valve shipped it for GoldSrc, carried a rewritten version into Source, and Mojang copied the Source wire format almost byte for byte into Minecraft. Facepunch went a different way for Rust. Between them those implementations cover most of what people actually run, including the majority of the Source-engine servers on the Counter-Strike server list.

What is already using it on your server

Almost every admin tool you have installed speaks RCON, usually without telling you:

What is not RCON: in-process administration. SourceMod, AMX Mod X, Oxide and Carbon run inside the server, take their instructions from players in-game, and never open a port. If you can do a job with an admin mod instead of an open RCON socket, do it there. The trade-offs between those frameworks are covered in the comparison of SourceMod, AMX Mod X and Oxide, and the short version for this article is that an admin mod gives you per-person permissions and an audit trail, which RCON structurally cannot.

The four packet types and the request ID trick

The Source RCON wire format is four fields, all little-endian:

  1. Size — a 32-bit integer counting every byte that follows, not including the size field itself. The minimum legal value is 10.
  1. ID — a 32-bit integer you choose freely per request.
  1. Type — a 32-bit integer, one of the four values below.
  1. Body — an ASCII string terminated by a null byte, followed by one more null byte as an empty second string.

Those two trailing nulls trip up people writing their own client. The format was defined with two strings in it; the second one is always empty and always present. Omit it and the server reads a malformed packet.

Note that the value 2 means two entirely different things depending on which way the packet is travelling. Nothing in the packet distinguishes them; direction is the only disambiguator. That is a design wart, not a subtlety you can be clever about.

Why the auth response reuses your request ID

There is no success flag and no error message on authentication. The server signals the result by what it puts in the ID field of the auth response. If it echoes the ID you sent, you are authenticated. If it sends -1 (0xFFFFFFFF), the password was wrong. That is the whole mechanism.

This matters practically. A client that does not check for -1 will report something vague like "connection closed by remote host" when the real problem is a typo in a password. It also means the ID field is a general request-matching device: you can send three commands with IDs 1, 2 and 3 and pair the responses to the right commands rather than assuming strict ordering. Most clients never bother, which is fine until you write a bot that fires several commands in flight at once.

The empty packet Source sends first

Source servers answer a successful auth with two packets: an empty SERVERDATA_RESPONSE_VALUE first, then the actual SERVERDATA_AUTH_RESPONSE. Minecraft sends only the auth response. This single difference breaks clients in both directions. A client written against Minecraft and pointed at a Source server reads the empty packet, treats it as the auth reply, sees an ID that does not match, and reports a bad password on a correct one. A client written against Source and pointed at Minecraft blocks waiting for a second packet that will never arrive, until its read timeout fires.

The 4096-byte limit that eats long output

A single response packet from a Source server caps at 4096 bytes. Plenty of everyday commands produce more than that: cvarlist on a modded server runs to tens of kilobytes, status on a 64-slot server that is actually full is a few kilobytes of player rows, and sm plugins list with 25 plugins loaded will pass the ceiling on its own.

When output exceeds the cap the server splits it across several SERVERDATA_RESPONSE_VALUE packets. The protocol contains no flag marking the last fragment. There is no length prefix for the whole response and no sequence number. This is the single largest hole in the design, and it is why so many hand-rolled clients quietly lie to you: they read one packet, print it, and return. You see 4 KB of a 30 KB answer with no indication that anything was cut.

The sentinel trick, and how it fails on Minecraft

The standard workaround exploits the server's own queueing. Immediately after sending your SERVERDATA_EXECCOMMAND, send a second packet from the client with type 0 and an empty body. Source queues it behind the real response, mirrors the empty packet back to you, and follows it with one more packet whose body is the four bytes 0x00 0x01 0x00 0x00. When you read that byte sequence, you know every fragment of the real response has already arrived. Concatenate what came before it and you have the complete output.

Minecraft does not do this. Vanilla replies to a packet type it does not recognise with a body reading Unknown request followed by the type in hex. That string is still usable as an end marker, but a client that hard-codes Valve's mirror behaviour will sit there waiting. If your Minecraft RCON tool truncates output or hangs on long commands, this mismatch is nearly always why.

There is a matching limit in the other direction. Request bodies larger than roughly 1,400 bytes get dropped on Source, so the idea of packing fifty sm_ban commands into one packet does not work. Send them as separate packets and pace them, because each one costs main-thread time on the server. If you need to move a large amount of text onto the box, write it to a file over SFTP and have the server exec it, which is one short command with a short response.

Source, GoldSrc, Minecraft and Rust do not speak the same RCON

"RCON" is a family name, not a specification. Four widely deployed variants matter.

Source engine

Counter-Strike 2, Counter-Strike: Source, Team Fortress 2, Garry's Mod, Left 4 Dead 2 and Day of Defeat: Source all use the binary TCP protocol described above. The listener sits on the same port number as the game, but over TCP rather than UDP, so a default install answers RCON on 27015/tcp while gameplay runs on 27015/udp. rcon_port moves it. Server-side, the relevant knobs are sv_rcon_maxfailures (default 10), sv_rcon_minfailures (5), sv_rcon_minfailuretime (30 seconds), sv_rcon_banpenalty (0 minutes) and sv_rcon_whitelist_address, which exempts one address from the failure counting. Note that default ban penalty: zero minutes means the ban survives only until the server decides otherwise, which is close to no protection at all. The Source servers on the CS2 server list and the Garry's Mod server list all ship with those defaults unless somebody changed them.

GoldSrc, which is worse

Counter-Strike 1.6, Half-Life, Day of Defeat and Team Fortress Classic use a completely different protocol that happens to share the name. It runs over UDP on the game port, and it is challenge-response: the client sends challenge rcon, receives a numeric challenge, then sends the challenge, the password and the command together in a single packet. The critical difference is that the password rides on every command packet, not once at the start of a session. Anyone able to observe a single command has your password permanently. Given that CS 1.6 still accounts for around 10,800 concurrent players across those 1,588 listed servers, this is not a museum piece.

Minecraft

Vanilla, Paper, Spigot and Fabric all use the Source wire format with three deviations: no empty packet before the auth response, Unknown request instead of the mirror sentinel, and no failure counting whatsoever. A wrong password closes the socket and that is the end of the server's reaction. Reconnect and guess again, as fast as you can open sockets.

There is also a binding gotcha. RCON gets its own port through rcon.port (default 25575, separate from the game's 25565) but in vanilla builds it does not get its own bind address: it follows server-ip from server.properties. You therefore cannot bind RCON to 127.0.0.1 while leaving the game port on 0.0.0.0. Use a firewall rule instead. If you are setting up a fresh box for one of the 4,230 servers on the Minecraft server list, do that before you set enable-rcon=true, not after.

Rust WebRCON

Rust does not use the binary protocol at all by default. With rcon.web 1 it opens a WebSocket on rcon.port (28016) and exchanges JSON messages shaped like {"Identifier":1,"Message":"players","Name":"WebRcon"}. Responses come back as JSON with a message body, an identifier and a type. The awkward part is authentication: the password is the WebSocket path, so you connect to ws://host:28016/YOURPASSWORD. It is plain ws://, not wss://, which means the password ends up in the URL, and URLs get written to proxy logs, browser history and error reports. Anyone running one of the servers on the Rust server list through a reverse proxy should assume that path is recorded somewhere.

The security model, which is that there is not one

Here is the part that justifies the article. A working RCON connection is arbitrary command execution on your game server. Not "a risk", not "a vector" — it is a console. With it an attacker can changelevel your server into oblivion, quit it in a loop, set sv_downloadurl to a host they control so your players fetch their files, add a logaddress that ships your logs offsite, or on Minecraft run /op and then any plugin command, including plugin commands that write to disk.

The protection standing between the internet and that console is one shared password sent in the clear. There are no user accounts, no per-command permissions, no rate limiting worth the name on most implementations, no second factor, and no identity in the logs. sv_rcon_log 1 records which command ran, never who ran it.

Why brute force is cheap

Do the arithmetic. A six-character lowercase password is about 309 million candidates. At a modest 200 attempts per second across a handful of parallel connections that is under three weeks, and nobody uses random six-character strings — they use the server name, the community name, or a dictionary word with a number on the end, which falls in minutes against a wordlist. Source at least counts failures. Minecraft does not count anything.

Nor does anyone need to find you. TCP 27015 and 27015-27020 are among the most scanned port ranges on the internet, and 25575 is scanned specifically because it is the Minecraft RCON default. Assume every address you own is swept daily. An open RCON port is not obscure, and the volume of connection attempts alone is enough to matter on a small box, which is one more reason to read the notes on stopping a DDoS on a small game server before you expose anything you do not have to.

The client-side footgun nobody warns you about

On Source and GoldSrc, rcon_password is also a client variable. If you set it in your personal config so you can type rcon status in-game, your client sends that password to whichever server you are currently connected to the moment you use the rcon command. Connect to somebody else's server with the variable still set, forget, type rcon, and a hostile operator has harvested your admin password without doing anything at all. It is passive, it is silent, and it has been collecting passwords for two decades. Set rcon_password per-server through a bind or a script, clear it afterwards, and never put it in autoexec.cfg.

The historical Source bugs

Source RCON has been patched repeatedly for the same class of problem. Malformed size fields caused bad allocations and crashed servers, which turned an unauthenticated TCP connection into a denial-of-service tool. Failure counting was bypassable by opening fresh connections rather than reusing one. The ban penalty shipped at zero. Each of these was fixed in turn, and the lesson generalises rather than expiring: a protocol with no encryption, no session concept and a parser that predates modern hardening is not something you want reachable from arbitrary addresses, patched or not.

How to actually lock RCON down

You do not have to stop using RCON. You have to stop letting strangers reach it.

Bind to localhost and tunnel over SSH

This is the correct answer for Source. Set rcon_address 127.0.0.1 so the listener never accepts a remote connection, then reach it through SSH:

ssh -N -L 27015:127.0.0.1:27015 admin@your-server

Point your RCON client at 127.0.0.1:27015 and it will work exactly as before, except the cleartext auth packet now travels inside an encrypted, key-authenticated tunnel. You get SSH's authentication in front of a protocol that has effectively none, at the cost of one extra process on your desktop. If several staff need access, give each of them their own SSH key and their own system user rather than sharing one login.

Firewall allowlist when you cannot bind locally

Minecraft's shared bind address makes the tunnel approach awkward, so use packet filtering instead. Two rules, in this order:

iptables -A INPUT -p tcp --dport 25575 -s 203.0.113.10 -j ACCEPT iptables -A INPUT -p tcp --dport 25575 -j DROP

The order is the whole point. A DROP placed above the ACCEPT blocks everyone including you. Allowlist your panel's address and your own static address, and nothing else. If your panel runs on the same machine, check whether it needs RCON at all: Pterodactyl's wings daemon attaches to the container's standard input and output, so its console works with RCON entirely disabled. Turn the port off rather than firewalling it.

Password hygiene, stated bluntly

Rate limiting and noticing an attack

Set sv_rcon_maxfailures 5 and give sv_rcon_banpenalty a real value in minutes, 60 being a reasonable start. Turn on sv_rcon_log 1 and point fail2ban at the console log with a filter matching failed RCON attempts, so repeated guessing gets the address dropped at the firewall rather than merely counted by the game. Then make sure someone sees it: an alert on a spike of authentication failures belongs in the same place as your availability checks, and the practical setups in the guide to game server monitoring and uptime extend to security events with no extra tooling. Worth stating plainly: JoinGG never uses RCON to reach a listed server. Every figure on the site comes from the same public query packet a player's client sends, which is described in full in the measurement methodology. If anything claiming to be a server list asks for your RCON password, that is not how server lists work.

RCON clients and tools, and what each is good at

There is no single best client. Pick by what you are doing, and read the third column before you install anything.

A rule of thumb that has aged well: if a job can be done in-process by an admin mod, or through a panel that authenticates real users, do it there and leave RCON for the cases that genuinely need the console. The community servers worth joining across the full JoinGG server list tend to be the ones where administration is boring and nothing is exposed that does not have to be. The scale of the thing is visible in the site-wide statistics: roughly 156,000 players are connected to listed servers at any given time, and each of those servers is one misconfigured port away from being somebody else's.

When RCON is the wrong tool

RCON gets reached for reflexively. Several common jobs are better done another way, and a couple should not be done at all.

The last one deserves a note. The A2S query protocol exists precisely so that outside observers can read a server's state without an authenticated console session. It is cheap, it is designed for it, and it does not require a password. If all you want is player count, map and hostname, query the server; do not log into it.

Close the port and keep the console

RCON is a good protocol for the job it was designed for, in the year it was designed. Read it as a console cable with a network jack soldered on rather than as a management API, and the correct handling falls out on its own: bind it locally, tunnel it, allowlist it, give it a long unique password, and never let that password appear anywhere else.

If you have inherited a server and do not know what state its RCON is in, work through it in this order. It takes about fifteen minutes.

  1. Find every copy of the password. Run grep -r rcon_password across the config directory, then check your panel, your bot's environment file, your backup archives and any repository you have pushed. Most leaks are copies somebody made, not packets somebody captured.
  1. Decide whether you need the port at all. If your panel attaches to container standard input, set enable-rcon=false or leave rcon_password empty and stop here.
  1. If you do need it, generate a fresh 24-character random password unique to that one server, and put it nowhere else.
  1. Bind to 127.0.0.1 where the engine allows it, and add the firewall pair, ACCEPT then DROP, where it does not.
  1. Set sv_rcon_maxfailures 5, a non-zero sv_rcon_banpenalty, and sv_rcon_log 1.
  1. Verify from outside. From an address that is not on your allowlist, nc -vz your-server 27015 should time out rather than connect.

That last step is the one people skip, and it is the only one that proves anything. A rule written into the wrong chain, a bind address set in a file the server does not read, and a host-level firewall silently overriding yours all look identical from inside the box: everything appears configured and the port is still open. Test it from somewhere else.

The protocol quirks in this article, the doubled type 2, the -1 auth failure, the 4096-byte fragments and the mirror sentinel that Minecraft does not send, account for most of the time people waste on RCON tooling. Knowing them turns a two-hour debugging session into a five-minute one. The security half is simpler still, because it reduces to a single sentence: the password crosses the network in the clear, so put something in front of it that does not.

Frequently asked questions

Is RCON encrypted?

No. Source RCON, Minecraft RCON and Rust WebRCON all send the password and every command as plain bytes on the wire. There is no TLS in any of the base protocols and no option to turn it on. Anything on the path between your client and the server reads both the password and the command output.

What port does RCON use?

Source engine servers listen for RCON on TCP using the same port number as the game, so 27015 TCP alongside 27015 UDP, moved with rcon_port. Minecraft uses a separate port set by rcon.port, default 25575 TCP. Rust WebRCON defaults to 28016 TCP. GoldSrc has no separate port at all: it answers on the game port over UDP.

How do I tell whether my RCON password was rejected?

Check the request ID on the auth response packet. On success the server echoes the ID your client sent. On failure it returns -1. There is no error string. A client that reports connection closed rather than bad password is one that never checked the ID, or one talking to Minecraft, which drops the socket after a failed auth.

Why does my RCON client cut off long command output?

A single response packet caps at 4096 bytes and the protocol has no flag marking the last fragment. Output from cvarlist, status on a full server, or sm plugins list runs past that and arrives split across several packets. A client that reads one packet and stops shows you the first 4 KB and no warning that anything is missing.

Can someone brute force an RCON password?

Yes, and it is cheap. Source counts failures through sv_rcon_maxfailures and can ban the source address, but the default ban penalty is 0 minutes. Vanilla Minecraft counts nothing at all and simply closes the socket, so an attacker reconnects and keeps guessing. Dictionary words and short passwords fall in minutes.

Should I use RCON or SSH to manage my server?

Both, for different jobs. SSH gives you the filesystem, the process, logs and backups, and it is authenticated with keys. RCON gives you the running game console and nothing else. Use SSH for anything involving files or restarts, and run RCON inside an SSH tunnel so its cleartext password never crosses an untrusted network.

Once the port is closed and the console is yours again, the rest is ordinary server operation: keep it running, keep it patched, and make sure people can find it. When it is ready for players you can add your server to the JoinGG list, and it will be polled hourly over its public query protocol with no credentials of any kind changing hands.

JoinGG lists 11,561 game servers across 31 games with servers currently online, polled hourly over each game's native query protocol. Figures in this article reflect measurements taken on 9 September 2026.

rconsource rconminecraft rconrcon_passwordgame server administrationwebrcon

More