Brazil's biggest MU Online portal — since 2003
Tutorial Intermediate Website

How to create a PK Clear system via website in MU Online

Build a PK Clear system via website in MU Online to remove the killer status from characters, with a secure stored procedure, optional charging, and protection against abuse.

GA Gabriel · Updated on Aug 12, 2025 · ⏱ 17 min read
Quick answer

In MU Online, killing other players outside of events turns your character into a killer (PK — Player Killer). That status brings unpleasant penalties: a chance to drop items on death, blocked access to NPCs in towns and, depending on the grade, guards that attack automatically. Traditionally, the p

In MU Online, killing other players outside of events turns your character into a killer (PK — Player Killer). That status brings unpleasant penalties: a chance to drop items on death, blocked access to NPCs in towns and, depending on the grade, guards that attack automatically. Traditionally, the player has to wait for the penalty time to pass or pay a specific NPC inside the game to clear the PK. Offering PK Clear via website is a valued convenience — and a source of monetization — that lets the player clear the status from their account panel in seconds.

This tutorial shows how to build that system securely, with the logic inside a SQL Server stored procedure and a lean PHP layer. As with reset, the key is to validate everything in the database, treat every form value as hostile, and prevent the operation from running while the character is online. The field names shown are an EXAMPLE from Season 6; the exact structure varies by version — always confirm your database schema before applying. If you haven't set up the server and website foundation yet, first see how to create a MU Online server.

Prerequisites

  • A working MU Online server with a GameServer and an accessible MuOnline database.
  • SQL Server (2008/2014/2017/2019) with SSMS and db_owner permission.
  • A website in PHP 7.4+ connected to the database via PDO (sqlsrv or dblib driver).
  • A working login/session system for the account panel.
  • A recent database backup before any UPDATE test.

Step 1 — Understand the PK status in the database

The killer status is stored in columns of the Character table. Before writing any code, find out the exact names in your version:

SELECT COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'Character'
  AND (COLUMN_NAME LIKE '%Pk%' OR COLUMN_NAME LIKE '%Kill%');

In a typical Season 6 EXAMPLE, the relevant fields are:

FieldPurpose"Clean" value
PkLevelPenalty grade3 (neutral) on most builds
PkCountNumber of accumulated kills0
PkTimeRemaining penalty time0
ConnectStatOnline status (0 = offline)used for blocking

Pay attention to the "neutral" value of PkLevel: on many Season 6 emulators, 3 means a common/no-PK character, while higher values indicate increasing killer grades. On other versions, neutral is 0. This varies by version — test with a staging character before defining the constant.

Step 2 — Create the PK Clear stored procedure

All the business logic (character ownership, online status, charging, limit) lives in the procedure, inside a transaction. PHP only calls it and interprets the return.

USE MuOnline;
GO

IF OBJECT_ID('dbo.WZ_PkClearViaSite', 'P') IS NOT NULL
    DROP PROCEDURE dbo.WZ_PkClearViaSite;
GO

CREATE PROCEDURE dbo.WZ_PkClearViaSite
    @AccountID   VARCHAR(10),
    @CharName    VARCHAR(10),
    @NeutralPk   INT = 3,       -- EXAMPLE: neutral value varies by version
    @ZenCost     BIGINT = 0
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

    DECLARE @Owner VARCHAR(10), @Online TINYINT, @PkLevel INT, @Money BIGINT;

    BEGIN TRANSACTION;

    SELECT @Owner = AccountID, @Online = ConnectStat,
           @PkLevel = PkLevel, @Money = Money
    FROM dbo.Character WITH (UPDLOCK, ROWLOCK)
    WHERE Name = @CharName;

    IF @Owner IS NULL OR @Owner <> @AccountID
    BEGIN
        ROLLBACK TRANSACTION;
        SELECT -10 AS Result, 'Character does not belong to this account.' AS Message;
        RETURN;
    END

    IF @Online <> 0
    BEGIN
        ROLLBACK TRANSACTION;
        SELECT -1 AS Result, 'Log out of the game before clearing PK.' AS Message;
        RETURN;
    END

    -- If already neutral, don't charge or change anything
    IF @PkLevel <= @NeutralPk
    BEGIN
        ROLLBACK TRANSACTION;
        SELECT -2 AS Result, 'This character has no PK.' AS Message;
        RETURN;
    END

    IF @ZenCost > 0 AND @Money < @ZenCost
    BEGIN
        ROLLBACK TRANSACTION;
        SELECT -3 AS Result, 'Insufficient Zen.' AS Message;
        RETURN;
    END

    -- Clear the PK status
    UPDATE dbo.Character
    SET PkLevel = @NeutralPk,
        PkCount = 0,
        PkTime  = 0,
        Money   = Money - @ZenCost
    WHERE Name = @CharName;

    INSERT INTO dbo.PkClearLog (AccountID, CharName, PkLevelAntes, ClearDate, Origem)
    VALUES (@AccountID, @CharName, @PkLevel, GETDATE(), 'SITE');

    COMMIT TRANSACTION;

    SELECT 1 AS Result, 'PK cleared successfully.' AS Message;
END
GO

And the log table:

CREATE TABLE dbo.PkClearLog (
    ID           INT IDENTITY(1,1) PRIMARY KEY,
    AccountID    VARCHAR(10),
    CharName     VARCHAR(10),
    PkLevelAntes INT,
    ClearDate    DATETIME,
    Origem       VARCHAR(10)
);

> The log is not optional. Cheap, unrecorded PK Clear encourages "ganking" — players who kill others at will because they know they can clear the penalty in one click. The log lets you detect accounts that clear PK repeatedly.

Step 3 — Reusable PDO connection

Keep the connection in a single file, with credentials outside version control.

<?php
// db.php
function getDB(): PDO {
    $dsn = 'sqlsrv:Server=' . (getenv('MU_DB_HOST') ?: '127.0.0.1') . ';Database=MuOnline';
    return new PDO($dsn, getenv('MU_DB_USER'), getenv('MU_DB_PASS'), [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]);
}

Step 4 — PK Clear form in the panel

List only the characters of the logged-in account, marking which ones have PK. This improves the experience (the player sees where they need to act) and avoids pointless clicks.

<?php
session_start();
require 'db.php';
if (empty($_SESSION['account_id'])) { header('Location: /login.php'); exit; }

if (empty($_SESSION['csrf'])) { $_SESSION['csrf'] = bin2hex(random_bytes(32)); }

$pdo = getDB();
$stmt = $pdo->prepare(
    'SELECT Name, PkLevel, PkCount FROM Character WHERE AccountID = ? ORDER BY Name'
);
$stmt->execute([$_SESSION['account_id']]);
$chars = $stmt->fetchAll();
$NEUTRO = 3; // EXAMPLE: adjust to your version's neutral value
?>
<form method="post" action="/pkclear_processar.php">
  <input type="hidden" name="csrf" value="<?= htmlspecialchars($_SESSION['csrf']) ?>">
  <select name="char" required>
    <?php foreach ($chars as $c):
        $temPk = ((int)$c['PkLevel'] > $NEUTRO); ?>
      <option value="<?= htmlspecialchars($c['Name']) ?>" <?= $temPk ? '' : 'disabled' ?>>
        <?= htmlspecialchars($c['Name']) ?>
        <?= $temPk ? '— PK level ' . (int)$c['PkLevel'] . ' (' . (int)$c['PkCount'] . ' kills)' : '— no PK' ?>
      </option>
    <?php endforeach; ?>
  </select>
  <button type="submit">Clear PK</button>
</form>

Step 5 — Process the clear securely

Validate the CSRF token, call the procedure with bound parameters, and handle the return. No business rule is decided in PHP.

<?php
session_start();
require 'db.php';
if (empty($_SESSION['account_id'])) { http_response_code(403); exit('Not authenticated.'); }

if (!hash_equals($_SESSION['csrf'] ?? '', $_POST['csrf'] ?? '')) {
    http_response_code(400); exit('Invalid token. Reload the page.');
}
unset($_SESSION['csrf']);

$char = trim($_POST['char'] ?? '');
if ($char === '' || strlen($char) > 10) { exit('Invalid character.'); }

$pdo = getDB();
$stmt = $pdo->prepare(
    'EXEC dbo.WZ_PkClearViaSite @AccountID = :acc, @CharName = :char,
                               @NeutralPk = :neutro, @ZenCost = :zen'
);
$stmt->execute([
    ':acc'    => $_SESSION['account_id'],
    ':char'   => $char,
    ':neutro' => 3,          // EXAMPLE
    ':zen'    => 3000000,    // EXAMPLE cost
]);
$res = $stmt->fetch();

echo (($res['Result'] ?? -99) == 1)
    ? 'Success: ' . htmlspecialchars($res['Message'])
    : 'Failure: ' . htmlspecialchars($res['Message'] ?? 'Unknown error.');

Step 6 — Prevent PK Clear with the character online

This is the same risk as reset via website: while the character is in the game, the GameServer keeps the data in memory and overwrites the database on the next save. If you clear the PK from the website with the char online, the clear is reverted — and the player may have paid for nothing. The procedure already blocks with ConnectStat <> 0, but confirm where that field lives in your version: it may be in Character or in MEMB_STAT (tied to the account). Adjust the query as needed and, ideally, instruct the player to log out of the game before clearing.

Step 7 — Cooldown and abuse protection

A PK Clear that's too accessible breaks the risk mechanic of PvP. Recommendations:

  1. Significant price: the cost in Zen or WCoin should hurt enough that killing players has a real consequence.
  2. Per-character cooldown: record a LastPkClear and block a new clear before X minutes.
  3. Per-account rate limiting: prevents scripts that clear PK in a loop.
  4. Audit the PkClearLog: monitor accounts with many clears in a row.
-- Detect accounts that cleared PK more than 5 times in the last 24h
SELECT AccountID, COUNT(*) AS Limpezas
FROM dbo.PkClearLog
WHERE ClearDate > DATEADD(HOUR, -24, GETDATE())
GROUP BY AccountID
HAVING COUNT(*) > 5
ORDER BY Limpezas DESC;

Common errors and fixes

ErrorLikely causeSolution
PK returns after entering the gameCharacter was onlineBlock with ConnectStat <> 0; require logout
PK Clear changes nothing visibleWrong neutral value (0 vs 3)Confirm the version's neutral with a test
Charge made but PK not clearedDebit in a separate queryDebit and clear in the same transaction
Character from another account clearedOwnership not validatedCompare AccountID in the procedure
Conversion error in PHPIncompatible parameter typeAlign PDO x procedure types
Injection through the char nameConcatenation in the queryAlways prepared statements

Launch checklist

  • Backup of the MuOnline database taken before testing.
  • PK fields (PkLevel, PkCount, PkTime) confirmed in your version.
  • Neutral value of PkLevel validated with a test character.
  • Stored procedure WZ_PkClearViaSite created and tested in SSMS.
  • PkClearLog table created and receiving records.
  • PDO connection with prepared statements, no concatenation.
  • Single-use CSRF token in the form and the processor.
  • Clear-blocking for an online character validated.
  • Ownership validation (AccountID) in two layers.
  • Cost and cooldown calibrated so as not to break PvP.
  • End-to-end test in staging before opening to the public.

With this system, PK Clear becomes a fast, profitable service without compromising the server's balance. The sensitive logic stays protected in the database, every operation is atomic and recorded, and the PHP layer stays small and hard to exploit. Adjust the neutral values, the cost, and the cooldown to your server's profile — and always test in staging before pushing to production.

Frequently asked questions

What exactly does PK Clear remove from the character?

It resets the killer (PK) status: the PK level, the kill counter, and the penalty time. The fields vary by version, but they're usually PkLevel, PkCount, and PkTime in the Character table.

Does the player need to be offline for the website PK Clear to work?

Yes, in most versions. If the character is online, the GameServer overwrites the database on save and the PK comes back. Block the operation when ConnectStat is anything other than 0.

What's the difference between PkLevel and PkCount?

PkLevel is the penalty grade (common, murderer, hero), which affects drop on death and town blocks. PkCount is the number of accumulated player kills. PK Clear usually resets both and PkTime.

Can I charge WCoin or Zen for PK Clear?

Yes. Debit it inside the same stored procedure and the same transaction that clears the PK, ensuring the charge only happens if the clear completes.

How do I stop players from abusing PK Clear to farm players without penalty?

Charge a significant amount, apply a per-character cooldown, and log every clear in a table to audit suspicious patterns.

GA
Guides & builds editor

Gabriel covers gameplay, class builds, PvP and progression. He tests every strategy on a live server before publishing.

Keep reading

Related articles