MySQL Server Installation Management & Backup/Restore in C# + Windows

Table of Contents


Manual Installation

Prerequisites

  • Microsoft Visual C++ 2019 Redistributable
  • MySQL ZIP archive from https://dev.mysql.com/downloads/mysql/

Extract & Structure

C:\mysql\
โ”œโ”€โ”€ bin\
โ”œโ”€โ”€ docs\
โ”œโ”€โ”€ include\
โ”œโ”€โ”€ lib\
โ”œโ”€โ”€ share\
โ”œโ”€โ”€ my.ini        โ† create this
โ””โ”€โ”€ data\         โ† created during initialization

Initialize Data Directory

cd C:\mysql\bin

# Blank root password
mysqld --initialize-insecure

# Random root password (check C:\mysql\data\<computername>.err)
mysqld --initialize

# With custom config location
mysqld --initialize-insecure --defaults-file=C:\other\my.ini

Set Root Password

mysql -u root -p -h localhost
ALTER USER 'root'@'localhost' IDENTIFIED BY 'your_password';

Configuration (my.ini)

Location: C:\mysql\my.ini (same level as bin folder)

Basic Configuration

[mysqld]
max_allowed_packet=1G
innodb_buffer_pool_size=500M
sql-mode="STRICT_TRANS_TABLES"

# MySQL 8.4+
mysql_native_password=ON

# MySQL below 8.4
authentication_policy=mysql_native_password

Full Configuration with Defaults

[client]
port=3306

[mysqld]
basedir=C:/mysql
datadir=C:/mysql/data
port=3306
character_set_server=utf8mb4
collation_server=utf8mb4_0900_ai_ci
default_storage_engine=InnoDB
innodb_buffer_pool_size=134217728    # 130MB default
max_allowed_packet=67108864           # 64MB default

Multiple Instance (Different Port)

[mysqld]
port=4001
basedir=D:/mysql/v8
datadir=E:/data/mysql/4001

Windows Service Management

Install Service (SC Command – Recommended)

sc create MySQL8 binPath= "C:\mysql\bin\mysqld.exe MySQL8" start= auto

With custom config:

sc create MySQL8 binPath= "C:\mysql\bin\mysqld --defaults-file=C:\mysql\my.ini MySQL8" start= auto

โš ๏ธ Important: Space AFTER = is required! Service name must appear at END of binPath.

Install Service (mysqld method)

mysqld --install "MySQL8" --defaults-file="C:\mysql\my.ini"
sc config "MySQL8" start= auto

Service Commands

net start MySQL8     # Start
net stop MySQL8      # Stop
sc delete MySQL8     # Remove
sc config MySQL8 binPath= "new\path"   # Modify

Manual Start/Stop (No Service)

# Start
mysqld

# Stop
mysqladmin -u root -p shutdown

Backup with mysqldump

Command Line Syntax

# Basic
mysqldump.exe -u root -pPASSWORD database_name --result-file="C:\backup.sql"

# Full options
mysqldump.exe -u root -pPASSWORD -h localhost -P 3306 --default-character-set=utf8mb4 --routines --events database_name --result-file="C:\backup.sql"

# Using config file (required for C# - hides password)
mysqldump.exe --defaults-file="C:\my.ini" --routines --events database_name --result-file="C:\backup.sql"

C# Implementation

public static async Task Backup()
{
    string fileMySqlDump = @"C:\mysql\bin\mysqldump.exe";
    string fileConfig = $@"C:\backup\my_temp_{DateTime.Now:ffff}.ini";
    string fileSql = @"C:\backup\backup.sql";
    string database = "database_name";

    // Create temp config
    File.WriteAllText(fileConfig, $@"[client]
user=root
password=password
host=localhost
port=3306
default-character-set=utf8mb4");

    string arg = $"--defaults-file=\"{fileConfig}\" --routines --events {database} --result-file=\"{fileSql}\"";

    var psi = new ProcessStartInfo
    {
        FileName = fileMySqlDump,
        Arguments = arg,
        UseShellExecute = false,
        CreateNoWindow = true,
        RedirectStandardOutput = true,
        RedirectStandardError = true
    };

    _ = Task.Run(() => { Thread.Sleep(1000); File.Delete(fileConfig); });

    using (var process = Process.Start(psi))
    {
        var errors = await process.StandardError.ReadToEndAsync();
        process.WaitForExit();
        if (process.ExitCode != 0 || !string.IsNullOrEmpty(errors))
            throw new Exception($"Error: {errors}");
    }
}

Restore with mysql.exe

โš ๏ธ CRITICAL: Command Line Parameter Rules

ContextQuoting Rule
CMD wrapperWrap ENTIRE mysql.exe + args in outer quotes
Direct mysql.exeEach argument in separate quotes, NO inner quotes
SOURCE pathNO quotes around file path inside argument

Method 1: CMD with File Redirection (<)

The < symbol is a shell operator (CMD function, not mysql.exe). It feeds file content to stdin.

Command:

mysql.exe --defaults-file="C:\my.ini" --database=dbname < "C:\backup.sql"

Full CMD wrapper:

cmd.exe /C ""C:\mysql\bin\mysql.exe" --defaults-file="C:\my.ini" --database=dbname < "C:\backup.sql""

C# Implementation:

string mysqlexe = @"C:\mysql\bin\mysql.exe";
string arg = $"/C \"\"{mysqlexe}\" --defaults-extra-file=\"{fileConfig}\" --database={database} < \"{sqlFile}\"\"";

var psi = new ProcessStartInfo
{
    FileName = "cmd.exe",
    Arguments = arg,
    UseShellExecute = false,
    CreateNoWindow = true,
    RedirectStandardOutput = true,
    RedirectStandardError = true
};

Method 2: Direct mysql.exe with SOURCE Command

Command:

mysql.exe "--defaults-extra-file=C:\my ini\my.ini" "--database=dbname" "--execute=SOURCE C:\backup\backup.sql"

โš ๏ธ NO inner quotes! Path with spaces works WITHOUT quotes inside the argument value.

Correct vs Wrong:

โœ… "--defaults-extra-file=C:\path to\my.ini"
โŒ "--defaults-extra-file="C:\path to\my.ini""

โœ… "--execute=SOURCE C:\my backup\backup.sql"
โŒ "--execute=SOURCE "C:\my backup\backup.sql""

C# Implementation:

string mysqlexe = @"C:\mysql\bin\mysql.exe";
string arg = $"\"--defaults-extra-file={fileConfig}\" \"--database={database}\" \"--execute=SOURCE {sqlFile}\"";

var psi = new ProcessStartInfo
{
    FileName = mysqlexe,
    Arguments = arg,
    UseShellExecute = false,
    CreateNoWindow = true,
    RedirectStandardOutput = true,
    RedirectStandardError = true
};

Method 3: Stream via StandardInput (No SOURCE, No CMD)

C# Implementation:

string arg = $"\"--defaults-extra-file={fileConfig}\" \"--database={database}\"";

var psi = new ProcessStartInfo
{
    FileName = mysqlexe,
    Arguments = arg,
    UseShellExecute = false,
    CreateNoWindow = true,
    RedirectStandardInput = true,   // โ† Key difference
    RedirectStandardOutput = true,
    RedirectStandardError = true
};

using (var process = Process.Start(psi))
{
    using (var reader = new StreamReader(sqlFile))
    {
        char[] buffer = new char[4096];
        int charsRead;
        while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0)
        {
            process.StandardInput.Write(buffer, 0, charsRead);
        }
        process.StandardInput.Close();
    }
    process.WaitForExit();
}

Config File Options

OptionDescription
--defaults-fileUse ONLY this config (ignores all others)
--defaults-extra-fileUse this IN ADDITION to default configs

Programmatic Start/Stop (C#)

Check Server Status

public static bool IsMySqlServerRunning()
{
    try
    {
        using (var conn = new MySqlConnection("Server=localhost;Port=3306;Uid=root;Pwd=password;"))
        {
            conn.Open();
            return true;
        }
    }
    catch { return false; }
}

Start Server

public static void StartMySqlServer()
{
    if (IsMySqlServerRunning()) return;

    var psi = new ProcessStartInfo
    {
        FileName = @"C:\mysql\bin\mysqld.exe",
        UseShellExecute = false,
        CreateNoWindow = true,
        RedirectStandardOutput = true,
        RedirectStandardError = true
    };

    // Don't WaitForExit - mysqld runs continuously
    Process.Start(psi);
}

Stop Server

public static bool StopMySqlServer()
{
    if (!IsMySqlServerRunning()) return true;

    string configFile = CreateTempConfigFile();

    var psi = new ProcessStartInfo
    {
        FileName = @"C:\mysql\bin\mysqladmin.exe",
        Arguments = $"--defaults-extra-file=\"{configFile}\" shutdown",
        UseShellExecute = false,
        CreateNoWindow = true,
        RedirectStandardOutput = true,
        RedirectStandardError = true
    };

    using (var process = Process.Start(psi))
        process.WaitForExit();

    File.Delete(configFile);

    // Verify (wait up to 3 seconds)
    for (int i = 0; i < 6; i++)
    {
        Thread.Sleep(500);
        if (!IsMySqlServerRunning()) return true;
    }
    return false;
}

public static string CreateTempConfigFile()
{
    string path = Path.Combine(Path.GetTempPath(), $"mysql_{DateTime.Now.Ticks}.cnf");
    File.WriteAllText(path, @"[client]
user=root
password=your_password
host=localhost
port=3306");
    return path;
}

Quick Reference

TaskExecutableKey Notes
Initializemysqld --initialize-insecureCreates data directory
Install Servicesc createSpace after =, name at end of binPath
Backupmysqldump.exeUse --result-file for output
Restore (CMD)cmd /C "mysql.exe ... < file"Wrap entire command in quotes
Restore (Direct)mysql.exe --execute=SOURCENO inner quotes in arguments
Start Servermysqld.exeDon’t wait for exit
Stop Servermysqladmin shutdownUse config file for credentials

Sources: