shadow1ng/fscan · error

mssql: invalid prelogin response packet type %d

Error message

mssql: invalid prelogin response packet type %d

What it means

The first packet of the prelogin response was not a TDS REPLY packet (type 4). After sending a prelogin packet the library expects the server to answer with packet type 4; any other type indicates the endpoint is not behaving like SQL Server or the stream is desynchronized.

Source

Thrown at plugins/services/mssql_raw.go:154

		_ = binary.Write(payload, binary.BigEndian, offset)
		_ = binary.Write(payload, binary.BigEndian, uint16(len(value)))
		offset += uint16(len(value))
	}
	payload.WriteByte(tdsPreloginTerminator)
	for _, key := range keys {
		payload.Write(fields[byte(key)])
	}

	return mssqlWritePacket(w, tdsPacketPrelogin, payload.Bytes())
}

func mssqlReadPrelogin(r io.Reader) error {
	packetType, payload, err := mssqlReadMessage(r)
	if err != nil {
		return err
	}
	if packetType != tdsPacketReply {
		return fmt.Errorf("mssql: invalid prelogin response packet type %d", packetType)
	}
	if len(payload) == 0 {
		return fmt.Errorf("mssql: empty prelogin response")
	}

	fields, err := mssqlParsePreloginFields(payload)
	if err != nil {
		return err
	}
	if _, ok := fields[tdsPreloginEncryption]; !ok {
		return fmt.Errorf("mssql: prelogin response missing encryption field")
	}
	return nil
}

func mssqlParsePreloginFields(payload []byte) (map[byte][]byte, error) {
	fields := make(map[byte][]byte)
	for pos := 0; ; pos += 5 {

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Confirm the port is a TCP SQL Server instance port (1433 or the instance's dynamic port), not UDP 1434 or a TLS-only frontend.
  2. If the server requires encryption, the client must negotiate TLS — prelogin response may differ; use a driver supporting ENCRYPT_ON.
  3. Check for proxies/load balancers that alter the first packet.
  4. Re-run with a packet capture to see the actual first byte of the response.
Defensive patterns

Strategy: validation

Validate before calling

// Validate the target speaks TDS before deep handshakes:
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, strconv.Itoa(port)), timeout)
if err != nil { /* not reachable */ }
_ = conn.Close()

Try / catch

res, err := mssqlRawLogin(ctx, host, port, user, pass, timeout)
if err != nil {
    if strings.HasPrefix(err.Error(), "mssql: invalid prelogin response packet type") {
        // endpoint is not SQL Server or requires TLS; try alternate port/driver
    }
}

Prevention

When it happens

Trigger: mssqlReadPrelogin gets a packet type other than 4 from mssqlReadMessage, e.g. the remote peer sent a data packet, an RST-adjacent protocol banner, or a redirect packet.

Common situations: Connecting to the wrong port (another service that echoes bytes); SQL Server Browser endpoints (UDP vs TCP confusion); TLS-wrapped SQL Server where the first bytes are a TLS record instead of a TDS packet.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/dfe6f7ea7211279a. Report an issue: GitHub.