Skip to content

mysqlx: StmtExecute response never reaches client after AuthOK in fresh sessions #5855

Description

@renecannao

Summary

After the frontend auth handshake completes successfully, the first SQL_STMT_EXECUTE (a plain SELECT 1) never produces a response frame back to the client. Surfaced while bringing the mysqlx-soak-g1 TAP group green — three of the soak tests (test_mysqlx_route_drop_inflight-t, test_mysqlx_soak_behavioral-t, test_mysqlx_soak_stress-t) all fail past the handshake stage for this reason.

Distinct from the auth/connect-surface bugs fixed in PR #5852 (commit b8a710c1f: MYSQL41 AuthContinue parser accepting standard X-Protocol shapes, start_connect adding DNS resolution, mapped-mode backend password fallback). Those three were necessary for the client to reach the SQL stage at all; this is what blocks it from completing.

Observed symptoms

Two failure shapes, possibly the same bug surfaced by different client timings:

Shape A — mysql-connector-python (mysqlx-soak-g1 behavioral/stress harnesses):

  • mysqlx.get_session(...) returns successfully (frontend auth OK)
  • proxysql log shows backend start_connect returning rc=1 EINPROGRESS, then check_connect rc=0 (TCP connect completes)
  • s.sql(\"SELECT 1\").execute() then hangs indefinitely
  • No further plugin log lines after the backend connect completes

Shape B — raw TAP client (test_mysqlx_route_drop_inflight-t):

  • Stage 1: 5/5 handshakes succeed (clients reach AuthOK)
  • Stage 2: exec_select_1 returns false on all 5 fds within ~160ms each → pre-drop SELECT 1 succeeded on 0/5 sessions
  • proxysql log shows the 5 handshakes — and then nothing. No start_connect lines fire for any of the 5 sessions during Stage 2, even though forward_to_backend should have triggered the lazy backend connection.

Hypotheses (not yet confirmed)

State machine transition after BACKEND_AUTH_DONE (see handler_connecting_server() in plugins/mysqlx/src/mysqlx_session.cpp, around the tail that sets status_ = WAITING_CLIENT_XMSG; to_process = true;). Candidates:

  1. The next handler tick isn't re-entering handler_waiting_client_msg / dispatch_client_message, so the buffered StmtExecute frame is never popped.
  2. forward_to_backend is entered but server_ds().write_to_net() doesn't actually write to the backend fd (e.g. server_ds_ not properly bound to backend_conn_->get_fd() after fresh auth).
  3. The backend response side (handler_waiting_server_msg) is never invoked because server_ds_ isn't subscribed for read events.
  4. The session is being marked healthy = false somewhere on the AuthOK→first-query transition and closed without logging.

Shape A and Shape B may diverge on which hypothesis applies — A clearly gets to BACKEND_AUTH_DONE; B may not even get the SELECT 1 into forward_to_backend (the absence of start_connect logs in Shape B is the most surprising data point).

Diagnostic plan

Targeted proxy_info traces at:

  • dispatch_client_message entry: log msg_type, status_, backend_conn_ != nullptr
  • forward_to_backend entry/exit: log server_ds().get_status(), backend_conn_->get_state(), whether the frame was enqueued
  • handler_waiting_server_msg entry: log how often it's called and whether server_ds_ has any data
  • Every healthy = false assignment post-send_auth_ok() (grep for the assignments and add a trace)

Plus tcpdump -i any -w /tmp/cap.pcap port 6603 or port 13306 from the test-runner container to confirm whether the SELECT 1 frame ever leaves ProxySQL toward the backend, and whether the backend ever responds.

Reproduction (local)

# In a worktree of v3.0 with PR #5852 merged:
make debug && PROXYSQL40=1 PROXYSQLGENAI=1 OPTZ=\"-O0 -ggdb -DDEBUG\" make -C plugins/mysqlx
WORKSPACE=\$(pwd) INFRA_ID=dev-soak-\$USER TAP_GROUP=mysqlx-soak-g1 test/infra/control/ensure-infras.bash
WORKSPACE=\$(pwd) INFRA_ID=dev-soak-\$USER TAP_GROUP=mysqlx-soak-g1 test/infra/control/run-tests-isolated.bash

# Or just Shape A:
docker run --rm --network dev-soak-\${USER}_backend python:3.11-slim bash -c \\
  'pip install mysqlx-connector-python -q && python3 -c \"
import mysqlx
s = mysqlx.get_session({\\\"host\\\":\\\"proxysql.dev-soak-${USER}\\\",\\\"port\\\":6603,
  \\\"user\\\":\\\"alice\\\",\\\"password\\\":\\\"alicepass\\\",
  \\\"ssl-mode\\\":\\\"DISABLED\\\",\\\"compression\\\":\\\"disabled\\\",\\\"auth\\\":\\\"MYSQL41\\\"})
print(\\\"OPEN\\\")
print(s.sql(\\\"SELECT 1\\\").execute().fetch_all())  # hangs here
\"'

Direct backend (bypassing ProxySQL, same alice creds, port 13306) works end-to-end, so the backend itself is fine.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions