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
- 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.
- If the server requires encryption, the client must negotiate TLS — prelogin response may differ; use a driver supporting ENCRYPT_ON.
- Check for proxies/load balancers that alter the first packet.
- 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
- Confirm the port is a TCP SQL Server endpoint (not UDP 1434 browser service).
- Check whether the instance requires forced encryption before using a plain prelogin.
- Test with sqlcmd/go-mssqldb to validate the endpoint first.
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
- mssql: prelogin response missing encryption field
- mssql: login acknowledgement not received
- mssql: empty prelogin response
- mssql: invalid prelogin option table
- mssql: truncated prelogin option
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/dfe6f7ea7211279a.
Report an issue: GitHub.