← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
tenable:61696 · CWE-1392 · Disclosed 2012-08-28

MySQL Default Account Credentials

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a master key left under the database doormat, but only if the door is actually reachable

Tenable plugin 61696 is not a version-specific software flaw; it is a positive authentication finding. Nessus says it successfully logged into a MySQL listener using one or more known credentials, and Tenable explicitly notes the plugin is generic: a hit on an account like scrutinizer only proves the MySQL server accepted that username/password, not that the related product is installed. Practically, any MySQL or MariaDB deployment that exposes TCP access and still permits one of these known credential sets is affected, regardless of software version.

The Critical label is too blunt here. The impact of a successful default-credential login can absolutely be severe—data theft, tampering, and sometimes privileged DB actions—but the real-world severity depends on whether attackers can reach port 3306, whether the accepted account is truly high privilege, and whether this is internet-facing or only reachable after lateral movement. Because the plugin already proved a working login, this is not low; but because it is a configuration weakness with meaningful exposure friction, it lands as HIGH, not blanket Critical.

"Confirmed default MySQL creds are serious, but this is usually an exposure and reachability problem—not a blanket Critical."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Find a reachable MySQL listener

An attacker first needs network path to the MySQL service, usually on TCP 3306. Commodity tooling like nmap mysql-info or broad scanners like Shadowserver/Shodan-style telemetry make exposed listeners easy to spot, but internal-only databases are a different story and usually require prior foothold or flat east-west reachability.
Conditions required:
  • MySQL/MariaDB is listening on a routable interface
  • Attacker has network path to TCP 3306
  • Firewall/security groups permit the connection
Where this breaks in practice:
  • Many enterprise databases are not internet-facing
  • Segmentation, host firewalls, and private subnets often block first contact
  • Managed database services may restrict source IPs or require proxies
Detection/coverage: Excellent for reachability. External attack-surface tools and simple port scans see the listener, but they do not prove default creds by themselves.
STEP 02

Try known credential pairs

Next the attacker uses a targeted credential check such as nmap mysql-empty-password, Metasploit auxiliary/scanner/mysql/mysql_login, or a purpose-built login script. Tenable's plugin is stronger than banner-only detection because it reports a successful authentication using a known credential set.
Conditions required:
  • A default or otherwise well-known MySQL credential is still valid
  • The server accepts password auth for that account
  • Authentication attempts are not blocked or rate-limited
Where this breaks in practice:
  • Many modern installs disable blank/anonymous access by default
  • PAM/socket/SSO-backed auth can make classic password guessing irrelevant
  • Account lockouts, connection limits, and source restrictions can slow or stop repeated attempts
Detection/coverage: Good if you have DB audit logs or network IDS watching failed/successful MySQL auth. Nessus gives high-confidence positive detection when it logs in.
STEP 03

Land an authenticated database session

Once a known credential works, the attacker gets the privileges of that specific MySQL account immediately. If the account is root or another broad admin account, confidentiality and integrity of the database are effectively gone on first login.
Conditions required:
  • The accepted account has meaningful privileges
  • The server does not restrict the account by host in a way that blocks the attacker
Where this breaks in practice:
  • Some default-ish application accounts are low privilege
  • Host-bound grants like 'user'@'localhost' can prevent remote abuse
  • Read-only service accounts reduce blast radius
Detection/coverage: Database audit logs can capture login source, user, and subsequent statements. EDR usually has weak visibility here unless the DB host is deeply instrumented.
STEP 04

Dump, alter, or weaponize data access

With DB access, attackers can exfiltrate tables, reset application secrets, create rogue users, or tamper with records. On some deployments, elevated MySQL privileges can be chained into file writes or operational disruption, but generic OS-level RCE is not guaranteed from this finding alone.
Conditions required:
  • The account can read sensitive schemas and/or modify data
  • Application or business data of value is stored in the instance
Where this breaks in practice:
  • Least-privilege grants can contain damage
  • Encrypted fields, row-level controls in the app tier, and monitoring can limit payoff
  • FILE/SUPER-style privilege escalation paths are not universal
Detection/coverage: Moderate. DLP, query auditing, anomaly detection, and app break-glass monitoring help, but many orgs still have blind spots for legitimate-looking SQL sessions.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo CISA KEV entry and no product-specific active campaign evidence tied to this generic plugin. This is a misconfiguration class that attackers routinely exploit whenever they can reach the listener.
Proof-of-concept availabilityPublic and trivial. Nmap ships mysql-empty-password; Metasploit documents MySQL login/bruteforce support; Tenable also marks the plugin as Exploit Available and references a Metasploit module.
EPSSN/A. This is not a clean single-CVE condition, so there is no meaningful FIRST EPSS score for the plugin itself.
KEV statusNot applicable / not listed. Plugin 61696 is a generic credential finding, not a single CVE-backed software defect.
Vendor score and vectorTenable shows CVSS v3 9.8 (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) and Critical, but that score is inherited from referenced CVEs and overstates the average enterprise reality for a reachability-dependent default-credential issue.
Affected scopeVersion-agnostic. Any reachable MySQL/MariaDB service that still accepts one of the known username/password sets tested by the plugin can trigger this finding.
Fixed versionNo patch version. Permanent remediation is to remove or rotate the account, restrict host-based grants, and eliminate unnecessary remote exposure; mysql_secure_installation is the relevant hardening path, not a code upgrade.
Scanning and exposure dataShadowserver actively scans for reachable MySQL and says the scan was announced on 2022-05-31 with a blog titled 'Over 3.6M exposed MySQL servers on IPv4 and IPv6'. Their report also states they only prove the listener is reachable, not successful DB access.
Disclosure / plugin datesTenable published plugin 61696 on 2012-08-28 and the current plugin page shows it updated on 2026-03-30.
Reporter / detection sourceTenable Nessus is the reporting source here, and this plugin is stronger than passive identification because it reports successful authentication with known credentials.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to HIGH (8.1/10)

The decisive factor is attacker position and reachability: this is only exploitable where a MySQL listener is reachable and still honors a known credential set. The plugin's positive login result makes it materially dangerous, but the population of truly exploitable enterprise deployments is narrower than a universal unauthenticated remote software flaw.

HIGH Downgrade from vendor Critical to HIGH
MEDIUM Final blast-radius estimate without knowing whether the listener is internet-facing or internal-only

Why this verdict

  • Confirmed auth is real risk: this is not hypothetical banner matching; Nessus says it logged into the database with a known credential.
  • Reachability trims the population: an attacker needs network path to MySQL first, which usually means internet exposure, weak internal segmentation, or prior foothold.
  • Vendor CVSS is inflated for this use case: Tenable's Critical score inherits a generic unauth-style impact model, but many enterprise MySQL services are not broadly reachable and some accepted accounts are not full admins.

Why not higher?

This is not a blanket unauthenticated RCE. The attacker must first reach the MySQL listener, and the practical impact depends heavily on whether the accepted account is root-level, app-limited, or host-restricted. That combination is serious, but it is narrower than the vendor's one-size-fits-all Critical label.

Why not lower?

A positive default-credential login on a database is never hygiene-only noise. If an attacker can reach the service, the compromise path is immediate and low-skill, and the resulting data exposure or tampering can be business-critical even without OS-level code execution.

05 · Compensating Control

What to do — in priority order.

  1. Block unnecessary MySQL exposure — Restrict TCP 3306 with host firewalls, security groups, and network ACLs so only approved app tiers and DBA jump hosts can connect. For a HIGH verdict, deploy this containment within 30 days; if any hit is internet-facing, do it the same day because exposure is the biggest amplifier.
  2. Remove or rotate the accepted account — Disable the specific account Nessus authenticated with, or rotate it to a unique secret stored in your vault; if it is a vendor/application bootstrap account, rename or delete it where possible. This is the permanent fix for a configuration issue and should be completed within 30 days for mitigation, not deferred behind general patching.
  3. Tighten host-based grants — Constrain MySQL accounts to expected source hosts, especially administrative users, so a stolen or guessed password cannot be used from arbitrary segments. Apply within 30 days because it directly reduces exploitability even if some weak account remains.
  4. Run mysql_secure_installation controls — Use MySQL's supported hardening workflow to remove anonymous users, block insecure defaults, and enable password validation where compatible. Treat this as a within-30-days hardening requirement for all self-managed MySQL estates.
  5. Alert on successful remote DB logins — Turn on or tune DB audit logging so remote logins by high-risk users like root, admin, or product-default service accounts generate detections. Implement within 30 days to catch the next miss before it becomes a breach.
What doesn't work
  • MFA does not help for native MySQL password authentication unless you have explicitly integrated a supported external auth flow; most default-credential cases bypass that idea entirely.
  • EDR alone is weak here because the abuse happens over a legitimate SQL protocol and may look like a normal client session, especially if the attacker never touches the OS.
  • Patching MySQL binaries does not fix this by itself because the problem is the account state and network exposure, not a version-specific code defect.
06 · Verification

Crowdsourced verification payload.

Run this from a DBA jump host or auditor workstation that can reach the target MySQL service and has the mysql CLI installed. Invoke it like python3 verify_mysql_default_creds.py --host db01.example.com --port 3306 --probe root: --probe admin:admin --admin-user auditor --admin-pass 'StrongPass!'; no OS admin rights are required, but optional --admin-user/--admin-pass need a MySQL account able to query mysql.user for deeper inspection.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# verify_mysql_default_creds.py
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN

import argparse
import os
import shutil
import subprocess
import sys
import tempfile

DEFAULT_PROBES = [
    'root:',
    'root:root',
    'admin:admin',
    'mysql:mysql',
    'scrutinizer:scrutinizer',
]


def run_mysql(host, port, user, password, query, connect_timeout=5):
    mysql_bin = shutil.which('mysql')
    if not mysql_bin:
        return None, 'mysql client not found in PATH'

    cmd = [
        mysql_bin,
        '--protocol=TCP',
        '-h', host,
        '-P', str(port),
        '-u', user,
        '--connect-timeout=' + str(connect_timeout),
        '--batch',
        '--raw',
        '--skip-column-names',
        '-e', query,
    ]

    env = os.environ.copy()
    env['MYSQL_PWD'] = password

    try:
        cp = subprocess.run(cmd, capture_output=True, text=True, env=env, timeout=connect_timeout + 5)
    except subprocess.TimeoutExpired:
        return None, 'mysql command timed out'
    except Exception as e:
        return None, str(e)

    if cp.returncode == 0:
        return cp.stdout.strip(), None
    return None, (cp.stderr or cp.stdout or 'mysql command failed').strip()


def parse_probe(s):
    if ':' not in s:
        return s, ''
    user, password = s.split(':', 1)
    return user, password


def inspect_mysql_user_table(host, port, admin_user, admin_pass):
    findings = []

    q1 = (
        "SELECT CONCAT(IFNULL(User,''),'@',IFNULL(Host,'')) "
        "FROM mysql.user WHERE User=''"
    )
    out, err = run_mysql(host, port, admin_user, admin_pass, q1)
    if err is None and out:
        for line in out.splitlines():
            findings.append(f'anonymous account present: {line}')

    q2 = (
        "SELECT CONCAT(User,'@',Host,' plugin=',IFNULL(plugin,''),' authlen=',"
        "CHAR_LENGTH(IFNULL(authentication_string,''))) "
        "FROM mysql.user "
        "WHERE User='root' AND Host NOT IN ('localhost','127.0.0.1','::1')"
    )
    out, err = run_mysql(host, port, admin_user, admin_pass, q2)
    if err is None and out:
        for line in out.splitlines():
            findings.append(f'remote root account present: {line}')

    q3 = (
        "SELECT CONCAT(User,'@',Host,' plugin=',IFNULL(plugin,''),' authlen=',"
        "CHAR_LENGTH(IFNULL(authentication_string,''))) "
        "FROM mysql.user "
        "WHERE User IN ('scrutinizer','admin','mysql','test')"
    )
    out, err = run_mysql(host, port, admin_user, admin_pass, q3)
    if err is None and out:
        for line in out.splitlines():
            findings.append(f'suspicious default-style account present: {line}')

    return findings


def main():
    ap = argparse.ArgumentParser(description='Verify MySQL default / known credential exposure')
    ap.add_argument('--host', required=True, help='Target MySQL host')
    ap.add_argument('--port', type=int, default=3306, help='Target MySQL port (default: 3306)')
    ap.add_argument('--probe', action='append', default=[], help="Credential probe in user:password form; may be repeated")
    ap.add_argument('--admin-user', help='Optional MySQL admin/audit username for mysql.user inspection')
    ap.add_argument('--admin-pass', help='Optional MySQL admin/audit password for mysql.user inspection')
    args = ap.parse_args()

    probes = args.probe[:] if args.probe else DEFAULT_PROBES[:]
    vulnerable_reasons = []
    unknown_reasons = []

    if not shutil.which('mysql'):
        print('UNKNOWN - mysql client not found in PATH')
        sys.exit(2)

    for probe in probes:
        user, password = parse_probe(probe)
        out, err = run_mysql(args.host, args.port, user, password, 'SELECT CURRENT_USER();')
        if err is None:
            vulnerable_reasons.append(f'login succeeded with known/default credential {user}:{password}')
        else:
            unknown_reasons.append(f'probe failed or rejected for {user}: {err}')

    if args.admin_user and args.admin_pass is not None:
        out, err = run_mysql(args.host, args.port, args.admin_user, args.admin_pass, 'SELECT 1;')
        if err is None:
            findings = inspect_mysql_user_table(args.host, args.port, args.admin_user, args.admin_pass)
            vulnerable_reasons.extend(findings)
        else:
            unknown_reasons.append(f'admin inspection failed: {err}')

    if vulnerable_reasons:
        print('VULNERABLE - ' + ' | '.join(vulnerable_reasons))
        sys.exit(1)

    if args.admin_user and args.admin_pass is not None:
        print('PATCHED - supplied probes failed and mysql.user inspection found no obvious anonymous/remote-root/default-style accounts')
        sys.exit(0)

    print('UNKNOWN - supplied probes failed, but no admin inspection was performed; this does not rule out other known credentials')
    sys.exit(2)


if __name__ == '__main__':
    main()
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, treat every hit on plugin 61696 as a credential exposure event, not a routine patch ticket. First, identify which findings are internet-facing or broadly reachable from user/server segments and apply containment under the noisgate mitigation SLA: for this HIGH verdict, block unnecessary MySQL exposure and disable/rotate the accepted account within 30 days—but if the listener is internet-exposed, patch / mitigate immediately, within hours. There is no vendor code patch here, so the permanent fix is account cleanup, host-grant tightening, and hardening (mysql_secure_installation-style controls); complete that under the noisgate remediation SLA of ≤180 days, with exposed or privileged-root hits handled first.

Sources

  1. Tenable Nessus Plugin 61696 - MySQL Default Account Credentials
  2. Tenable Plugin 61696 Changelog
  3. MySQL 8.0 Reference Manual - mysql_secure_installation
  4. MySQL 8.0 Secure Deployment Guide
  5. Nmap NSE - mysql-empty-password
  6. Shadowserver - Accessible MySQL Server Report
  7. Metasploit Documentation - MySQL
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.