How to detect and ban bots automatically in MU Online
Build an automatic bot-detection pipeline for your MU Online server by combining database pattern analysis, in-game CAPTCHA, packet telemetry and scheduled banning, without flooding legitimate players with false positives.
Bots are the silent plague of MU Online servers. While you sleep, a single bot user runs ten clients on XP spots, piles up Zen and rare items, crashes market prices and discourages the legitimate players who play by hand. In 72 hours an undefended server becomes scorched earth economically. The temp
Bots are the silent plague of MU Online servers. While you sleep, a single bot user runs ten clients on XP spots, piles up Zen and rare items, crashes market prices and discourages the legitimate players who play by hand. In 72 hours an undefended server becomes scorched earth economically. The temptation is to enable an aggressive automatic ban — and the result is usually worse: false positives ban the hardcore player who spends 16 hours farming honestly, generate complaints and burn the server's reputation. The right way out is a layered pipeline: collect signals automatically, score each account, challenge the suspects with a CAPTCHA and reserve the permanent ban for unequivocal cases. This guide shows how to build that pipeline. All table names, columns and thresholds are examples that vary by season/emulator — calibrate them with your server's real data.
Prerequisites
- SQL Server Management Studio (SSMS) connected to the
MuOnlinedatabase. - SQL Server Agent enabled for scheduled jobs.
- Administrative access to the GameServer and the ConnectServer.
- Knowledge of your build's schema: names of
MEMB_INFO,MEMB_STAT,Character, and the connection and XP columns. - A test environment (or test account) to validate before running in production.
- A full database backup before any change.
- Ideally, native CAPTCHA/anti-bot support in the emulator or an anti-cheat module.
> Run the whole pipeline in log mode (without banning) for at least 48 to 72 hours before enabling any automatic ban. This calibration phase is what separates a system that protects from one that destroys the player base.
The philosophy: layered detection with scoring
No single signal proves an account is a bot. One player may farm a lot; another may stay online all day; a third may repeat the same route. What gives away the bot is the combination of these signals. That's why the pipeline assigns points to each indicator and only acts when the sum crosses a threshold. The table below shows an example scoring scheme.
| Detected signal | Points | Rationale |
|---|---|---|
| Kills/hour above the human ceiling sustained for 2h+ | 30 | Volume impossible by hand |
| Continuous session above 20 hours | 25 | 24/7 bot |
| Near-zero position variance | 20 | Fixed automated route |
| Zero chat messages in a long session | 10 | Absence of social behavior |
| Failed in-game CAPTCHA | 40 | Almost unequivocal signal |
| Multiple clients on the same IP above the limit | 15 | Bot farm |
With this scheme, an account that merely farms a lot accumulates 30 points — suspicious, but not bannable. If it also keeps a 22-hour session (25) and fails the CAPTCHA (40), it reaches 95 and becomes a clear case. The weights and thresholds vary by season/emulator; adjust them by observing the accounts at the top of your legitimate ranking.
Step 1 — Build the scoring infrastructure
Start with two tables: one for detection events and one for accumulated score per account.
USE MuOnline;
GO
CREATE TABLE dbo.Bot_Score (
AccountID VARCHAR(10) PRIMARY KEY,
TotalScore INT NOT NULL DEFAULT 0,
LastUpdate DATETIME DEFAULT GETDATE(),
Status TINYINT DEFAULT 0 -- 0=monitoring,1=challenged,2=banned,3=false positive
);
GO
CREATE TABLE dbo.Bot_Event (
EventID INT IDENTITY(1,1) PRIMARY KEY,
AccountID VARCHAR(10) NOT NULL,
CharName VARCHAR(10) NULL,
Signal VARCHAR(60) NOT NULL, -- e.g. KILLS_HORA, SESSAO_LONGA
Points INT NOT NULL,
Detail VARCHAR(200) NULL,
CreatedAt DATETIME DEFAULT GETDATE()
);
GO
Each time a check finds a signal, it writes an event to Bot_Event and adds the points to Bot_Score. This preserves the evidence trail — indispensable if a player contests the ban.
Step 2 — Behavioral detection via SQL
The cheapest and most powerful layer is behavioral analysis in the database itself. The stored procedure below scans online accounts and records the main signals.
USE MuOnline;
GO
CREATE PROCEDURE dbo.SP_Bot_Scan
AS
BEGIN
SET NOCOUNT ON;
-- Signal 1: kills/hour above the ceiling, sustained for 2h+
INSERT INTO dbo.Bot_Event (AccountID, CharName, Signal, Points, Detail)
SELECT c.AccountID, c.Name, 'KILLS_HORA', 30,
'PkCount=' + CAST(c.PkCount AS VARCHAR)
FROM Character c
INNER JOIN MEMB_STAT s ON c.AccountID = s.memb___id
WHERE s.ConnectStat = 1
AND DATEDIFF(HOUR, s.ConnectTM, GETDATE()) >= 2
AND (c.PkCount / NULLIF(DATEDIFF(HOUR, s.ConnectTM, GETDATE()), 0)) > 1000;
-- Signal 2: continuous session above 20 hours
INSERT INTO dbo.Bot_Event (AccountID, CharName, Signal, Points, Detail)
SELECT s.memb___id, c.Name, 'SESSAO_LONGA', 25,
CAST(DATEDIFF(HOUR, s.ConnectTM, GETDATE()) AS VARCHAR) + 'h'
FROM MEMB_STAT s
INNER JOIN Character c ON s.memb___id = c.AccountID
WHERE s.ConnectStat = 1
AND DATEDIFF(HOUR, s.ConnectTM, GETDATE()) > 20;
-- Consolidate the score
MERGE dbo.Bot_Score AS tgt
USING (
SELECT AccountID, SUM(Points) AS Pts
FROM dbo.Bot_Event
WHERE CreatedAt >= DATEADD(HOUR, -24, GETDATE())
GROUP BY AccountID
) AS src
ON tgt.AccountID = src.AccountID
WHEN MATCHED THEN
UPDATE SET TotalScore = src.Pts, LastUpdate = GETDATE()
WHEN NOT MATCHED THEN
INSERT (AccountID, TotalScore) VALUES (src.AccountID, src.Pts);
PRINT 'Bot scan complete: ' + CAST(GETDATE() AS VARCHAR);
END;
GO
Note that the consolidation uses a 24-hour window: old points expire, preventing a player from accumulating eternal suspicion over one atypical farming day.
Step 3 — Schedule the scan in SQL Server Agent
- In SSMS, expand SQL Server Agent → right-click Jobs → New Job.
- Name:
Bot_Scan_Automatico. - Steps tab → New Step: type
Transact-SQL, databaseMuOnline, commandEXEC dbo.SP_Bot_Scan;. - Schedules tab → New Schedule: daily frequency, sub-frequency every 15 minutes.
- Confirm that the
SQL Server Agentservice is Running inservices.msc.
A 15-minute interval balances detection freshness with database load. Very large servers can space it to 30 minutes.
Step 4 — Targeted in-game CAPTCHA
The CAPTCHA is the most decisive confirmation layer, because a dumb bot simply doesn't answer. The classic mistake is to ask all players at a fixed interval, which annoys the base. The smart approach is to fire the challenge only at accounts with a suspicious score.
If your emulator has a native anti-bot with CAPTCHA (common from Season 6 onward), configure it to trigger by suspicion where possible:
[AntiBot]
Enable = 1
QuestionEnable = 1
QuestionInterval = 1800 ; 30-min base for suspects
QuestionTimeout = 120 ; time to answer (seconds)
WrongAnswerLimit = 2 ; errors before punishing
Punishment = 1 ; 0=kick, 1=temp ban, 2=perma ban
The questions live in a plain text file, one per line in the format question,answer:
How much is 6 plus 5?,11
What color is blood?,red
How many days are in a week?,7
What month comes after June?,july
Flag in your pipeline who was challenged and record the result. A CAPTCHA failure is worth many points precisely because it's almost unequivocal:
-- Record a CAPTCHA failure (called by the emulator hook or manually)
INSERT INTO dbo.Bot_Event (AccountID, CharName, Signal, Points, Detail)
VALUES ('suspiciousAccount', 'NickBot', 'CAPTCHA_FALHOU', 40, '2 consecutive errors');
> Keep the answers without accents and case-insensitive. Many Brazilian players type without accents and with inconsistent capitalization; requiring "Brasília" with an accent generates false positives among honest people.
Step 5 — Packet telemetry and per-IP limit
The network layer complements the behavioral one. On the ConnectServer, limit simultaneous connections per IP and protect against flooding — bot farms tend to run many clients from the same address.
[ServerInfo]
MaxConnectionPerIP = 4 ; simultaneous accounts per IP
PacketFloodProtection = 1
MaxPacketsPerSecond = 60 ; ceiling per connection
Adjust MaxConnectionPerIP carefully: LAN houses and families legitimately share an IP. A value between 3 and 5 usually balances it. Memory-injection detection, client integrity (Main.exe checksum) and speed reading depend on your build's anti-cheat module and are not covered by pure SQL.
Step 6 — Threshold-based banning, with review
Now the piece that closes the pipeline: acting on the score. Split it into two levels — automatic challenge for a medium score and ban with review for a high score.
USE MuOnline;
GO
CREATE PROCEDURE dbo.SP_Bot_Enforce
AS
BEGIN
SET NOCOUNT ON;
-- Level 1: 50-89 points -> flag for CAPTCHA challenge
UPDATE dbo.Bot_Score
SET Status = 1
WHERE TotalScore BETWEEN 50 AND 89 AND Status = 0;
-- Level 2: 90+ points -> ban and disconnect
UPDATE m
SET m.bloc_code = 1
FROM MEMB_INFO m
INNER JOIN dbo.Bot_Score b ON m.memb___id = b.AccountID
WHERE b.TotalScore >= 90 AND b.Status IN (0,1);
UPDATE s
SET s.ConnectStat = 0
FROM MEMB_STAT s
INNER JOIN dbo.Bot_Score b ON s.memb___id = b.AccountID
WHERE b.TotalScore >= 90;
UPDATE dbo.Bot_Score
SET Status = 2
WHERE TotalScore >= 90 AND Status IN (0,1);
PRINT 'Enforce complete: ' + CAST(GETDATE() AS VARCHAR);
END;
GO
Even at level 2, keep a human review at first: run in log mode, see who would be banned and check manually for a few days. Only then enable the automatic action — and even so, review the queue daily. This is the same principle of responsible moderation that applies to any punishment; if you haven't structured your moderation commands yet, it's worth starting with the basics of how to set up a MU Online server and the manual ban layer before automating.
Step 7 — Review query and false-positive reversal
Every morning, review who the system caught:
SELECT b.AccountID, b.TotalScore, b.Status,
STRING_AGG(e.Signal, ', ') AS Sinais
FROM dbo.Bot_Score b
LEFT JOIN dbo.Bot_Event e
ON e.AccountID = b.AccountID
AND e.CreatedAt >= DATEADD(HOUR, -24, GETDATE())
WHERE b.Status IN (1,2)
GROUP BY b.AccountID, b.TotalScore, b.Status
ORDER BY b.TotalScore DESC;
If you identify a false positive, reverse it and flag it so the system won't reoffend:
UPDATE MEMB_INFO SET bloc_code = 0 WHERE memb___id = 'honestAccount';
UPDATE dbo.Bot_Score SET Status = 3, TotalScore = 0 WHERE AccountID = 'honestAccount';
Common errors and fixes
| Problem | Likely cause | Fix |
|---|---|---|
| Too many false positives | Thresholds calibrated for another profile | Raise the kills/hour ceiling and the ban threshold; watch the legitimate ranking |
| Bots go unnoticed | Single-signal detection, bot randomizes movement | Sum multiple signals; add a targeted CAPTCHA |
| Scan inserts no events | Different column/table name in the build | Check the schema with INFORMATION_SCHEMA.COLUMNS |
| CAPTCHA annoys legitimate players | Fixed global-interval trigger | Fire the CAPTCHA only at accounts with a suspicious score |
| Job won't run | SQL Server Agent stopped or without permission | Check services.msc and the job history in SSMS |
| Ban doesn't prevent login | Wrong block column | Confirm the real name (bloc_code, block_code, IsBlock) in the schema |
| Banned account stays online | Forgot to clear ConnectStat | Include the disconnect UPDATE in the enforce |
Launch checklist
Bot_ScoreandBot_Eventtables createdSP_Bot_Scanvalidated in the test environmentBot_Scan_Automaticojob scheduled and Agent running- Scoring scheme calibrated with the server's real data
- In-game CAPTCHA configured and triggering by suspicion
- CAPTCHA questions without accents and case-insensitive
- Per-IP connection limit adjusted on the ConnectServer
SP_Bot_Enforcerunning in log mode for 48-72h before banning- Daily review routine for the suspect queue defined
- False-positive reversal process documented
- Evidence (events) retained for at least 30 days
- Database backup taken before enabling in production
Bot detection that works isn't the most aggressive — it's the most disciplined. By collecting signals automatically, scoring in layers, challenging before punishing and reserving the ban for clear cases, you clean the real bots off your server without turning every dedicated player into a victim. That balance is what keeps the economy healthy and the player base trusting your server.
Frequently asked questions
Can you ban bots 100% automatically without risk?
Not with full safety. Full automation generates false positives that ban legitimate players and destroy the server's reputation. The recommended approach is automatic in detection and evidence collection, but with a human review window or a scoring system with a high threshold before a permanent ban. A 100% automatic ban is only acceptable for unequivocal signals, such as a failed answer on a repeated CAPTCHA.
How do I tell a bot from a dedicated player who plays many hours?
Human players have variance: irregular breaks, spot changes, sporadic chat, reaction times that fluctuate. Bots are metronomic — the same route, the same interval between kills, zero social interaction, continuous sessions of 20 hours or more. Robust detection cross-references several signals instead of looking at just one, precisely so it doesn't punish the legitimate hardcore player.
Doesn't an in-game CAPTCHA annoy players?
If poorly calibrated, yes. The key is the frequency and the trigger. Instead of asking everyone every 20 minutes, fire the CAPTCHA only at accounts that have already accumulated suspicion points from other signals. That way the honest player rarely sees a question, while the suspect is challenged frequently. The ideal interval varies by season/emulator and by your audience's profile.
Can bots evade movement-pattern detection?
Advanced bots add random noise to mimic humans, which defeats detection based on a single signal alone. That's why effective defense is layered: even if the bot randomizes its movement, it tends to fail the CAPTCHA, keep sessions that are too long or generate an impossible volume of kills. No single layer is enough; the combination is what works.
Do I need an external anti-cheat or does the database solve it?
The database solves the behavioral layer (kills/hour, time online, XP patterns) and is where you start. But packet telemetry, client integrity checks and memory-injection detection require support from the emulator or an external anti-cheat module. Full coverage combines SQL analysis with whatever client-side protection your build offers.