MySQL-compatible access

Query weather data with the tools you already use

Connect a MySQL client or library directly to GribStream. Your API token is the password, datasets appear as databases, and weather data is returned as ordinary MySQL rows.

Public beta. We do not yet recommend this connection for production workloads, and behavior may change during beta. Please report issues or send feedback by email, or join us on Discord.
On this page

Start here

You only need a GribStream API token and a MySQL-compatible client or library.

  1. Create a free API token or use an existing token.
  2. Use gribstream as the username and the API token as the password.
  3. Select a dataset such as gfs as the database and connect.
mysql --host=mysql.gribstream.com \
  --port=3307 \
  --user=gribstream \
  --password \
  --database=gfs \
  --quick

The MySQL CLI prompts for the token, keeping it out of shell history. In this command, --quick tells the CLI to print rows as they arrive instead of buffering the complete result. Other clients use different settings for incremental results.

MySQL queries use the same API token and quota as HTTP API queries. Usage is based on the weather data read to answer the query. If you are unsure which dataset to use, browse the model catalog; gfs is a useful global starting point.

Why MySQL?

Languages and tools with a MySQL driver can use that familiar connection to query GribStream. You do not need to operate a MySQL server, import weather files, or learn a new client library.

The connection is read only and purpose-built for weather data. Datasets appear as databases, weather fields are discoverable, and unsupported SQL returns a clear error.

Bring your toolsUse a command line, application, notebook, or database integration.
Browse the catalogFind datasets, weather fields, units, and exact selectors before querying.
Request what you needChoose the times, places, and weather values you want returned as rows.

Find a weather column, then query it

Each GribStream weather parameter appears as a dataset-specific MySQL column. After choosing a dataset, discover its columns before writing the query:

SHOW FULL COLUMNS FROM gfs.timeseries;

In the result, copy the Field value you need. The Comment gives its human-readable name, native units, and exact GS_VALUE(...) equivalent. For GFS 2 m temperature, the column is tmp_2_m_above_ground.

These three forms identify the same weather parameter. The weather column is the simplest SQL form; GS_VALUE is the exact-selector fallback when translating an existing HTTP API request or building a dynamic selector. The JSON form is the selector shown on model pages.

MySQL weather column
tmp_2_m_above_ground
Exact GS_VALUE fallback
GS_VALUE(
  'TMP',
  '2 m above ground',
  ''
)
HTTP API selector
{
  "name": "TMP",
  "level": "2 m above ground",
  "info": ""
}

Copy weather column names from SHOW FULL COLUMNS or gribstream.selector_columns rather than constructing them yourself. Most are readable; long or colliding names receive a deterministic suffix. Exact selector strings remain case-sensitive.

This returns the next six hours of GFS 2 m temperature for one point:

SELECT forecasted_time,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time BETWEEN NOW() AND NOW() + INTERVAL 6 HOUR
  AND lat = 40.758
  AND lon = -73.985
  AND lead_time BETWEEN '0h' AND '48h'
ORDER BY forecasted_time
LIMIT 100;

This weather column is published in Kelvin. Check its Comment or the catalog for units rather than inferring them from the column name or alias.

The result is made of ordinary rows. Values below are illustrative:

forecasted_time       temp_k
2026-08-07 12:00:00   298.4
2026-08-07 13:00:00   299.1
2026-08-07 14:00:00   299.7

Use the catalog discovery workflow to search columns by parameter name, inspect units, and recover the exact JSON selector or GS_VALUE expression when you need it.

If the connection already selected gfs, use FROM timeseries. Otherwise qualify the table as gfs.timeseries.

Start from a working query

Choose the example closest to your goal, expand it, and change only the dataset, discovered weather column, times, or locations you need. Copy column names from SHOW FULL COLUMNS instead of guessing how a selector is normalized.

Query several named locations over a time range
SELECT forecasted_time, name, lat, lon,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-13T06:00:00Z'
  AND (lat, lon, name) IN (
        (40.758, -73.985, 'Times Square'),
        (29.7604, -95.3698, 'Houston'),
        (51.5072, -0.1276, 'London')
      );
Query a regular latitude-longitude grid

Smaller grid_step values select more points and consume more quota. Start coarse and narrow the area before increasing resolution.

SELECT forecasted_time, lat, lon,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-13T06:00:00Z'
  AND lat BETWEEN 25 AND 50
  AND lon BETWEEN -125 AND -66
  AND grid_step = 1;
Query a few exact, non-contiguous forecast times
SELECT forecasted_time,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time IN (
        '2026-07-13T00:00:00Z',
        '2026-07-13T06:00:00Z',
        '2026-07-14T18:00:00Z'
      )
  AND lat = 40.758
  AND lon = -73.985;
Query forecasts from specific model runs
SELECT forecasted_at, forecasted_time,
       tmp_2_m_above_ground AS temp_k
FROM gfs.runs
WHERE forecasted_at BETWEEN '2026-07-13T00:00:00Z'
                        AND '2026-07-13T12:00:00Z'
  AND lead_time BETWEEN '0h' AND '48h'
  AND lat = 40.758
  AND lon = -73.985
ORDER BY forecasted_at, forecasted_time;
Reproduce the forecasts available before a historical cutoff
SELECT forecasted_at, forecasted_time,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-14T00:00:00Z'
  AND forecasted_at <= '2026-07-12T18:00:00Z'
  AND lat = 40.758
  AND lon = -73.985
ORDER BY forecasted_time;
Query selected members of an ensemble
SELECT forecasted_time, member,
       tmp_2_m_above_ground AS temp_k
FROM gefsatmos.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-13T12:00:00Z'
  AND member IN (0, 1, 2)
  AND lead_time BETWEEN '0h' AND '48h'
  AND lat = 40.758
  AND lon = -73.985;
Convert a value and keep only rows matching a threshold
SELECT forecasted_time,
       tmp_2_m_above_ground AS temp_k,
       temp_k - 273.15 AS temp_c
FROM gfs.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-14T00:00:00Z'
  AND lat = 40.758
  AND lon = -73.985
  AND temp_c BETWEEN 18 AND 24;
Find the warmest grid points for one forecast time
SELECT forecasted_time, lat, lon,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time = '2026-07-13T18:00:00Z'
  AND lat BETWEEN 25 AND 50
  AND lon BETWEEN -125 AND -66
  AND grid_step = 0.5
ORDER BY temp_k DESC
LIMIT 20;

Connect from your language

Choose your language below. Each example connects securely, runs the same small weather query, and reads its rows. Store the token in an environment variable or secret manager; never commit it in a connection string.

MySQL 8 command-line client. TLS is negotiated automatically; add --quick for incremental output.

mysql \
  -h mysql.gribstream.com -P 3307 \
  -u gribstream -p -D gfs \
  --quick

For large results, use your driver's row iterator, streaming mode, or equivalent so it does not collect the entire result in memory.

Choose timeseries or runs

Every dataset schema exposes the same two weather-table shapes. Choose the table from the question you are answering, not from the columns you want returned.

timeseries

Choose this for the best eligible forecast at each requested valid time.

Filter byforecasted_time

runs

Choose this to inspect predictions from one or more specific model runs.

Filter byforecasted_atandlead_time

forecasted_at is the model initialization time. forecasted_time is the valid time being predicted. lead_time is their difference in hours; it can be selected or filtered.

Example: query model-run history
SELECT forecasted_at, forecasted_time, lat, lon,
       tmp_2_m_above_ground AS temp_k
FROM gfs.runs
WHERE forecasted_at BETWEEN '2026-07-13T00:00:00Z'
                        AND '2026-07-13T12:00:00Z'
  AND lead_time BETWEEN '0h' AND '48h'
  AND lat = 40.758
  AND lon = -73.985
ORDER BY forecasted_at DESC, forecasted_time ASC;
Available columns, query controls, and freshness metadata
ColumnMeaningNotes
datasetDataset code that produced the rowAlso the MySQL schema name
forecasted_atModel initialization timeOn timeseries, <= is the only supported run-cutoff operator
forecasted_timeValid time being predictedThe primary time column for timeseries
lat, lon, nameResolved point and optional labelname is nullable
memberEnsemble member identifierMeaningful only for ensemble datasets
index_updated_atLatest source-data update associated with the rowOptional freshness metadata; distinct from both forecast timestamps
lead_time, grid_stepForecast lead time in hours and requested grid spacing in degreesSelectable and filterable; grid_step is NULL for enumerated points
Dataset-specific weather columnsNative weather values such as tmp_2_m_above_groundDiscover with SHOW FULL COLUMNS; values are DOUBLE

Select index_updated_at to see the latest source-data update associated with each row. It is freshness metadata, not model initialization time; use forecasted_at to identify the model run.

SELECT forecasted_at, forecasted_time, index_updated_at,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-13T06:00:00Z'
  AND lat = 40.758
  AND lon = -73.985
ORDER BY forecasted_time;

Discover datasets, weather columns, and exact selectors

Do not guess column names, parameter levels, or units. Find a dataset, inspect its weather columns, and use the exact selector mapping only when you need the API form or GS_VALUE fallback.

1. Find a dataset

SELECT code, full_name, provider, min_lead_time, max_lead_time,
       is_ensemble, member_count, members, parameter_count
FROM gribstream.datasets
WHERE code LIKE '%gfs%'
ORDER BY code;
Check archive coverage and cadence before a large historical query
SELECT code, archive_start, archive_window, rolling_window,
       time_resolution, run_cadence, min_lead_time, max_lead_time,
       catalog_updated_at
FROM gribstream.datasets
WHERE code = 'gfs';

archive_start and archive_window describe published coverage; a rolling window can move forward. catalog_updated_at shows when the catalog metadata was refreshed. Select index_updated_at when row-level freshness matters.

2. Browse its weather columns

SHOW FULL COLUMNS FROM gfs.timeseries LIKE '%tmp%';

3. Search mappings or use an exact selector

SELECT short_name, full_name, units, has_code_table, variation_count
FROM gribstream.parameters
WHERE dataset = 'gfs'
  AND (short_name = 'TMP' OR full_name LIKE '%temperature%')
ORDER BY short_name
LIMIT 20;
SELECT column_name, full_name, units, name, level, info,
       selector_json, gs_value_sql
FROM gribstream.selector_columns
WHERE dataset = 'gfs'
  AND column_name = 'tmp_2_m_above_ground';

gribstream.selector_columns maps each weather column to its human-readable name, units, JSON selector, and equivalent GS_VALUE expression. It requires one exact dataset predicate.

Use the generated column_name for ordinary SQL. Use GS_VALUE(name, level, info) when you need a direct one-to-one translation from an API selector. This gefsatmosmean selector has a non-empty info value, so all three arguments are required:

JSON parameter selector
{
  "name": "CAPE",
  "level": "surface",
  "info": "ens mean"
}
Equivalent MySQL expression
GS_VALUE(
  'CAPE',
  'surface',
  'ens mean'
)

Model pages continue to show the canonical JSON selector and its exact GS_VALUE fallback. Copy generated SQL column names from the live schema, where collisions and long identifiers have already been resolved.

4. Find comparable signals across datasets

Shared parameters list common weather concepts, output units, and the datasets that support them. Use this catalog before comparing models, then resolve the exact selector tuple for each dataset instead of assuming that selector names match.

SELECT code, label, units, supported_datasets
FROM gribstream.shared_parameters
WHERE code = 'temperature_2m';
Example: calculate 10 m wind speed

After discovering the exact 10 m wind-component selectors for ifsoper, combine them with func.Hypot:

SELECT forecasted_time,
       v_10u_sfc AS u_component,
       v_10v_sfc AS v_component,
       func.Hypot(u_component, v_component) AS wind_speed
FROM ifsoper.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-13T06:00:00Z'
  AND lat = 48.8566
  AND lon = 2.3522
ORDER BY forecasted_time;
Machine-readable syntax and MySQL discovery commands

Use these when you want the connection itself to describe its SQL syntax and examples:

SELECT topic, supported_syntax, example, notes
FROM gribstream.sql_dialect
ORDER BY topic;
SELECT name, description, `sql`
FROM gribstream.query_examples
ORDER BY name;

Standard MySQL commands such as SHOW TABLES, SHOW COLUMNS, DESCRIBE, and SHOW CREATE TABLE are also available. SHOW FULL COLUMNS includes concise weather descriptions and exact GS_VALUE mappings:

SHOW FULL COLUMNS FROM gfs.timeseries;
Catalog tables
  • gribstream.datasets
  • gribstream.parameters
  • gribstream.parameter_variations
  • gribstream.selector_columns
  • gribstream.shared_parameters
  • gribstream.sql_dialect
  • gribstream.query_examples

Metadata queries support projections or *, DISTINCT, ORDER BY, LIMIT with a non-negative offset, and bounded combinations of =, !=, LIKE, IN, and null checks.

Values, calculations, and filters

Calculated columns use familiar SQL expressions and can refer to aliases defined earlier in the select list. Alias a weather column first, then reuse that alias. Keep unit conversions explicit:

SELECT forecasted_time,
       tmp_2_m_above_ground AS temp_k,
       temp_k - 273.15 AS temp_c
FROM gfs.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-13T12:00:00Z'
  AND lat = 40.758
  AND lon = -73.985
  AND (temp_c BETWEEN 18 AND 30 OR temp_c IS NULL);

Weather-value conditions support BETWEEN, numeric IN, null checks, parentheses, NOT, and boolean combinations. Join time, location, lead-time, member, and model-run conditions with AND; use OR only within weather-value conditions.

Functions and more complex calculations

Familiar numeric functions include ABS, CEIL/CEILING, FLOOR, ROUND, SQRT, POW/POWER, MOD, and TRUNCATE. Point labels support LOWER/LCASE, UPPER/UCASE, TRIM, and Unicode-aware CHAR_LENGTH. MySQL's byte-counting LENGTH is not supported; use CHAR_LENGTH for names.

SELECT forecasted_time,
       ugrd_10_m_above_ground AS u,
       vgrd_10_m_above_ground AS v,
       func.Hypot(u, v) AS wind_speed
FROM gfs.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-13T12:00:00Z'
  AND lat = 40.758
  AND lon = -73.985
  AND wind_speed > 5;

Additional GribStream expression functions use the explicit func. namespace. Expressions support literals, parentheses, unary operators, arithmetic, comparisons, and boolean combinations. See the expression reference for registered func. calls and arguments.

Units, data types, and missing values

Weather parameter columns and GS_VALUE return native units exactly as published in the catalog; choosing an alias does not convert the value. Inspect has_code_table in gribstream.parameters before treating a coded field as a continuous measurement.

Weather values, calculated expressions, latitude, and longitude are returned as MySQL DOUBLE. Timestamp columns are DATETIME(6); dataset, point name, and member identifiers are strings. Missing numeric or timestamp values become SQL NULL. Test them with IS NULL or IS NOT NULL; = NULL is not supported.

Prepared statements

Normal MySQL placeholders work in selectors, calculations, timestamps, coordinates, members, and weather filters. Relative time functions are evaluated when the prepared statement executes, not when it is prepared.

SELECT forecasted_time AS valid_time,
       GS_VALUE(?, ?) AS temp_k,
       temp_k - ? AS temp_c
FROM gfs.timeseries
WHERE forecasted_time BETWEEN ? AND ?
  AND lat = ?
  AND lon = ?
  AND temp_c BETWEEN ? AND ?
LIMIT 100;
Bounded DISTINCT results

Weather queries may use SELECT DISTINCT ... LIMIT n. Distinctness applies to the complete selected row. It cannot be combined with ORDER BY, and the query may still read the complete bounded selection before it knows that no more unique rows exist. Use it for bounded deduplication, not as a substitute for narrowing time and location.

SELECT DISTINCT name,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-13T06:00:00Z'
  AND (lat, lon, name) IN (
        (40.758, -73.985, 'Times Square'),
        (29.7604, -95.3698, 'Houston')
      )
LIMIT 100;

Time ranges, relative time, and time zones

timeseries.forecasted_time is valid time. runs.forecasted_at is model initialization time. Ranges require both bounds and include both endpoints when written with BETWEEN.

For adjoining windows, prefer a half-open range such as forecasted_time >= start AND forecasted_time < end. It avoids returning the boundary instant twice when consecutive queries are combined.

SELECT forecasted_at, forecasted_time,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time BETWEEN NOW() - INTERVAL 2 DAY AND NOW()
  AND forecasted_at <= NOW() - INTERVAL 6 HOUR
  AND lat = 40.758
  AND lon = -73.985
LIMIT 100;
Supported relative-time functions and timestamp formats

NOW(), CURRENT_TIMESTAMP, and UTC_TIMESTAMP() are evaluated once per statement in UTC; fractional precision such as NOW(6) is accepted. DATE_ADD, ADDDATE, DATE_SUB, SUBDATE, and infix + INTERVAL/- INTERVAL support fixed integer units from microseconds through weeks. Calendar months and years are intentionally excluded because their duration varies.

Timestamp literals accept a date, a MySQL datetime, ISO T form, or RFC 3339 with an offset. A literal without an offset is UTC unless it is the input wall time to CONVERT_TZ.

Select exact, non-contiguous times

Use = for one exact time and IN for several non-contiguous times. Use forecasted_time on timeseries and forecasted_at on runs. The query cookbook includes a complete example.

Query a local calendar day and handle daylight saving time
SELECT forecasted_time,
       CONVERT_TZ(forecasted_time, 'UTC', 'Europe/Paris') AS paris_time,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time >=
        CONVERT_TZ('2026-10-25 00:00:00', 'Europe/Paris', 'UTC')
  AND forecasted_time <
        CONVERT_TZ('2026-10-26 00:00:00', 'Europe/Paris', 'UTC')
  AND lat = 48.8566
  AND lon = 2.3522
LIMIT 100;

Named IANA zones account for daylight-saving transitions. The Paris range above spans the 25-hour fall-back day on October 25, 2026; the same half-open pattern spans the 23-hour spring-forward day on March 29 correctly. Input wall times are converted to UTC immediately; ambiguous or nonexistent local times fail clearly. Result-side conversion also accepts forecasted_at and index_updated_at. Keep the original UTC column when a fall-back day may display the same local clock time twice. Projected timezone aliases are presentation-only and cannot be used in WHERE.

Connections remain in UTC. SET time_zone accepts UTC-equivalent values, SYSTEM, or DEFAULT; use CONVERT_TZ when you need local timestamps.

Use a historical model-run cutoff

On timeseries, forecasted_at <= timestamp excludes newer model runs. It is the only supported operator for that column on timeseries; use index_updated_at when data freshness is the question. The query cookbook includes a complete historical-cutoff example.

Points, grids, lead times, and ensembles

Use one coordinate pair for a point, a tuple list for several named points, or latitude and longitude bounds with grid_step for a regular grid. The query cookbook includes complete examples of each shape.

  • One point: use lat = value AND lon = value.
  • Several points: use (lat, lon) or (lat, lon, name) with IN.
  • A grid: bound both coordinates and set grid_step in degrees. Smaller steps select more points and consume more quota.
Lead-time filters

Use quoted durations such as lead_time = '24h'. BETWEEN selects a closed range; paired >=/< comparisons express a half-open range; and a single comparison supplies only a minimum or maximum. Duration strings include forms such as '90m', '24h', or '168h'.

Ensemble-member filters

Check is_ensemble and the members JSON array in gribstream.datasets before selecting members; do not assume that every dataset is an ensemble or that member identifiers have the same range. The query cookbook includes a selected-members example.

Keep queries efficient

Quota usage is based on the weather data read to evaluate a query, not the number of rows returned. A condition on a weather value or calculated alias—such as temp_c > 30—can remove rows from the result only after those values have been read. A large query can therefore consume substantial quota even when its value filters return very few rows.

Conditions on forecast time, location, lead time, and ensemble member reduce the data selected. The following choices have the greatest effect:

  • Use timeseries unless you specifically need history from multiple model runs.
  • Keep time ranges short or use an exact time list.
  • Select only the weather parameter columns you need.
  • Prefer exact points to a broad grid; when using a grid, choose an appropriate grid_step.
  • Bound lead_time and select only the ensemble members you need.

Use ordering for exploration

ORDER BY is mainly intended for interactive sessions and data exploration, where receiving an immediately readable result is worth some additional work. For a bounded query, ordering first by the primary time column can usually return rows incrementally. Use forecasted_time for timeseries or forecasted_at for runs, choose either direction, and add selected columns or aliases as secondary keys when needed.

SELECT forecasted_time AS valid_time, name, lat, lon,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-13T12:00:00Z'
  AND (lat, lon, name) IN (
        (40.758, -73.985, 'Times Square'),
        (29.7604, -95.3698, 'Houston'),
        (51.5072, -0.1276, 'London')
      )
ORDER BY valid_time DESC, temp_k DESC, name ASC;

For runs, begin with forecasted_at and bound both sides of lead_time. If an ordered result is too large to process safely, narrow the selection or remove ORDER BY and sort it in your application.

For backfills and other high-volume data pulls, omit ORDER BY. If order matters, sort the data after receiving it. This avoids making server-side sorting the throughput limit, especially when a broad selection is combined with weather-value filters.

Global rankings

An order beginning with a weather value must consider the complete selection before it can return any rows, so it requires LIMIT. Use this form for rankings rather than incremental output. The query cookbook includes a complete warmest-points example.

Use LIMIT for result size, not quota

LIMIT is useful for keeping interactive output small, but it does not define the amount of weather data read. Filtering and ordering may read far more data than the final result contains. Use the selection controls above when you need to reduce quota usage.

Advanced: validate a query with EXPLAIN

Most queries do not need EXPLAIN. Prefix a weather query with it to validate the statement and see diagnostic information without retrieving weather rows or consuming query quota. It is mainly useful for troubleshooting and support.

EXPLAIN
SELECT forecasted_time, lat, lon,
       tmp_2_m_above_ground AS temp_k
FROM gfs.timeseries
WHERE forecasted_time BETWEEN '2026-07-13T00:00:00Z'
                          AND '2026-07-13T12:00:00Z'
  AND (lat, lon) = (40.758, -73.985)
LIMIT 100;

Streaming, cancellation, and errors

Rows become available incrementally. Whether you see them immediately depends on the MySQL client or library, so use its unbuffered, streaming, iterative, or chunked result interface for large queries. The exact setting is client-specific; the client reference appendix links to each library's documentation.

  • Client disconnect: closing the connection cancels its active query.
  • MySQL CLI: press Ctrl+C to stop the active query.
Application cancellation and concurrent queries

A MySQL connection has one active statement at a time. Consume or close its result before reusing that connection; use a connection pool when an application genuinely needs concurrent queries. Every pooled connection authenticates independently.

Use the driver's cancellation API or cancelable query context; its name and behavior depend on the client. To cancel explicitly, run KILL QUERY <connection_id> from another connection using the same API token. The target connection remains reusable.

MySQL error codes

Errors use ordinary MySQL error responses so existing clients surface them naturally:

SituationMySQL codeWhat you see
SQL syntax1064A parser or validation error near the unsupported input.
Unsupported SQL1235A focused explanation of the unsupported construct.
Invalid token1045Access denied during connection authentication.
Cancelled query1317Query execution was interrupted.
Rate limit1226The message explains when to wait before retrying, when available.

Troubleshooting

Reduce bandwidth for a large result

For large pulls, enable MySQL protocol compression if your client or driver supports it. The setting differs by client; use the official documentation in the appendix.

MySQL CLI: add --compression-algorithms=zstd when connecting.

From any client, check the negotiated compression with:

SHOW SESSION STATUS LIKE 'Compression%';
The TLS connection fails certificate or hostname verification

Connect to mysql.gribstream.com, not its IP address, and use an up-to-date trusted CA bundle. Keep identity verification enabled; disabling it can hide a wrong hostname, interception, or an incomplete trust store. Trust-store and verification settings vary by client; see the client reference appendix.

The connection times out

Confirm that your network allows outbound TCP connections to mysql.gribstream.com on port 3307. Corporate firewalls and restricted notebook environments sometimes block non-default database ports.

A weather column is unknown or an exact selector is rejected

Run SHOW FULL COLUMNS FROM <dataset>.timeseries and copy the Field value instead of guessing it. For exact-selector SQL, copy gs_value_sql from gribstream.selector_columns; selector strings are case-sensitive and must not be translated or normalized.

A value has an unexpected scale, unit, or meaning

GribStream returns the selector's published native values. Recheck units, description, and has_code_table in the catalog, and confirm the exact level and info. Unit conversions are explicit calculated columns; an AS alias alone never changes the data.

A time range, time zone, or ordered query is rejected

Provide both time bounds. Convert named-zone wall-time boundaries to UTC with CONVERT_TZ; do not guess an ambiguous or nonexistent DST time. For an unsafe ordered shape, narrow the selection or remove ORDER BY and sort in the consuming application.

No rows appear until the query finishes

Your client is buffering the result. Select its unbuffered, streaming, iterative, or chunked result mode. MySQL CLI: reconnect with --quick. pandas: pass chunksize. For other clients, follow the result-handling documentation in the appendix.

A query receives MySQL error 1226

Reduce concurrency or wait for the time given in the error message before retrying. An immediate retry loop only extends the rate limit.

Use the connection as a self-describing tool for AI agents

Any generic MySQL database connector—including one exposed as an MCP tool—can connect to mysql.gribstream.com:3307. Provide the API token through the connector's secret configuration.

Give the agent the skill file below. The schema and catalog tables let it discover datasets, weather columns, units, exact selector mappings, dialect rules, and ready-to-run examples before it builds a query.

  1. Read gribstream.sql_dialect and gribstream.query_examples.
  2. Search gribstream.datasets, then inspect SHOW FULL COLUMNS for the chosen weather table.
  3. Use gribstream.selector_columns when an exact JSON selector or GS_VALUE mapping is needed.
  4. Build and execute the smallest bounded query that answers the question.
  5. Use EXPLAIN only to validate or troubleshoot a query.

Download the GribStream MySQL agent skill for the complete workflow, syntax boundaries, and recovery rules.

Supported SQL and deliberate boundaries

Weather queries

  • SELECT from timeseries and runs
  • Discovered weather columns and exact GS_VALUE fallbacks
  • Calculated aliases, familiar numeric/string functions, and documented func. calls
  • Time ranges and lists, points, grids, members, lead times
  • Weather-value boolean filters
  • Time-first ordering or bounded global top-N
  • Bounded DISTINCT, prepared statements, and optional EXPLAIN diagnostics

Intentionally unsupported

  • Writes, DDL, transactions, and locks
  • Joins, subqueries, aggregation, and grouping
  • SELECT * for weather results
  • Unbounded global sorting and order expressions
  • Non-zero weather-result offsets
  • Unlisted MySQL functions and implicit SQL coercions

These boundaries keep queries predictable, results streamable, and errors clear instead of accepting SQL with surprising behavior.

Beta compatibility policy

Stable during beta. We intend to preserve the connection and token-authentication flow, dataset schemas, timeseries and runs, bounded time and location selection, released weather-column names, exact GS_VALUE selectors, calculated columns, filters, streaming, cancellation, and catalog discovery.

May evolve. Additional convenience functions, advanced ordering and DISTINCT forms, timezone presentation, prepared-statement details, and behavior specific to third-party tools may change as we learn from beta use.

How changes ship. Additive capabilities may appear without advance notice. If documented behavior must change incompatibly, we will make reasonable efforts to publish release notes and notify active users we can identify. This beta has no production availability commitment and may be withdrawn.

The running adapter publishes its release, source revision, and SQL compatibility version in gribstream.adapter_info. Released weather-column names are append-stable: adding a catalog selector will not rename a column already published by this adapter.

Beta release notes

August 8, 2026 — adapter 0.1.0, SQL dialect 1. Initial public beta contract with secure MySQL-compatible access, discoverable weather columns, bounded weather queries, streaming, and cancellation.

Full compatibility matrix
SurfaceSupported formsBoundary
SessionUSE, VERSION(), DATABASE(), UTC time functions, common session variables and status probesCompatibility behavior, not a full MySQL server variable set
DiscoverySHOW DATABASES, SHOW TABLES, SHOW FULL COLUMNS, DESCRIBE, SHOW CREATE TABLEOnly GribStream schemas and tables
Metadata SELECTProjections or *, DISTINCT, boolean filters, ORDER BY, LIMIT and non-negative offsetsCatalog and information_schema tables only
Weather SELECTExplicit fixed and discovered weather columns, GS_VALUE fallback, calculations, bounded predicates, filters, and limited DISTINCTNo weather *, joins, subqueries, grouping, or aggregation
OrderingUp to eight selected keys; time-first ordering or a limited global top-NNo expressions, ordinals, duplicate keys, or unbounded global sort
Prepared statementsNormal ? placeholders in selectors, expressions, times, locations, members, and filtersUp to five prepared statements per connection
Advanced diagnosticsEXPLAIN SELECT ...Validates without executing; EXPLAIN ANALYZE is unsupported
CancellationKILL QUERY connection_id from a connection using the same tokenCannot inspect or cancel another token's work

Appendix: client configuration references

TLS, compression, result buffering, cancellation, timeouts, and connection pooling are configured by the client or driver rather than by SQL. Use the documentation for the library you actually connect with.

ClientOfficial documentationUseful for
MySQL CLIClient options and connection optionsTLS, compression, --quick, timeouts, and other CLI flags
PythonConnector/Python connection arguments and pandas read_sqlTLS, compression, pooling, connection options, and chunked DataFrames
JavaConnector/J configuration propertiesTLS, compression, timeouts, and JDBC behavior
C# / .NETMySqlConnector connection optionsTLS, compression, pooling, and timeouts
Gogo-sql-driver/mysql documentationDSN options, TLS, compression, timeouts, and pooling
Node.jsmysql2 documentationConnections, TLS, pools, prepared statements, and result streaming
Rustmysql crate documentationTLS, compression, pools, and row iteration
CMySQL C API guideConnection and result APIs
DuckDBDuckDB MySQL extensionEnvironment-variable credentials, read-only ATTACH, TLS, remote-table queries, and mysql_query
DBeaverMySQL connection settings and SSL configurationMySQL 8 connection, SSL, certificate trust, and database navigation