Skip to content

Cookie preferences

We use cookies for our own analytics, to see how our campaigns perform and, if you allow it, to load content from other services such as the Google site search. We never sell your data. Necessary cookies keep the site working and cannot be switched off. See our Cookie Policy for details and our Privacy Policy for how we handle personal data.

Security, load balancing and remembering your cookie choice.

Show us which pages people read, how they find the site and where they get stuck, so we can improve it (Google Analytics, Microsoft Clarity).

Show us which of our ad campaigns bring visitors to the site and remember the campaign or partner link you arrived from (Google Ads, LinkedIn, Meta, partner program). We do not use these cookies to build advertising profiles.

Load the site search from Google when you use it. Google sets its own cookies and shows ads in the search results.

© 2026 The ThingsBoard Authors
2.1k Try for free

ThingsBoard Cloud

Choose your data region

Your data stays in the region you choose, for residency and compliance. No credit card required.

Rather run it yourself? Install on your own servers

ODBC

The ODBC Connector periodically queries an ODBC-compatible database for new data and forwards the results to ThingsBoard as device attributes and telemetry. It can also call SQL stored procedures and functions in response to RPC commands from ThingsBoard.

To enable this connector, add it to the connectors list in tb_gateway.json — see the General Configuration reference.

The connector reads its settings from a JSON file. Below is a full example:

{
"connection": {
"str": "Driver={PostgreSQL};Server=localhost;Port=5432;Database=thingsboard;Uid=postgres;Pwd=postgres;",
"attributes": {
"autocommit": true,
"timeout": 0
},
"encoding": "utf-8",
"decoding": {
"char": "utf-8",
"wchar": "utf-8",
"metadata": "utf-16le"
},
"reconnect": true,
"reconnectPeriod": 60
},
"pyodbc": {
"pooling": false
},
"polling": {

Before using the ODBC Connector, complete the following installation steps:

  1. Install the ODBC runtime:

  2. Install the ODBC driver for the specific database (PostgreSQL, MySQL, etc.) the gateway needs to connect to.

  3. Register the driver:

Required. Configures how to connect to the ODBC database and how to handle reconnections.

Parameter Default Description
str ODBC connection string
attributes (Optional) Connection attributes
encoding utf-16 Encoding used when writing string data to the database
decoding (Optional) Encoding used when reading string data from the database — see below
reconnect true Reconnect after a database error
reconnectPeriod 60.0 Seconds between reconnect attempts (floating-point for sub-second precision)

Optional. Tunes low-level connection behaviour via pyodbc connection attributes (for example, autocommit or timeout).

Optional. Controls how string data and metadata read from the database are decoded.

Parameter Default Description
char utf-16 Encoding for regular string (CHAR/VARCHAR) columns
wchar utf-16 Encoding for Unicode string (NCHAR/NVARCHAR) columns
metadata utf-16 Encoding for column names and other metadata

Optional. Exposes pyodbc module-level attributes that control the underlying Python ODBC library.

"pyodbc": {
"pooling": false,
"native_uuid": true
}

Optional. Specifies a custom uplink data converter class name. When omitted, the built-in converter is used.

"converter": "CustomOdbcUplinkConverter"

Required. Controls how often the database is queried, what SQL statement to run, and which column is used to advance through the result set between polling iterations.

Parameter Default Description
query SQL SELECT statement to fetch data — see requirements below
period 60.0 Polling interval in seconds (floating-point for sub-second precision)
iterator Iterator configuration — see below

Requirements for the query statement:

  1. Must be a valid SQL SELECT statement compatible with the target database dialect.
  2. Must include the device column in the SELECT list.
  3. Must include the iterator column in the SELECT list.
  4. Must include all attributes and/or timeseries columns in the SELECT list.
  5. The WHERE clause must filter rows using the iterator column (the ? placeholder receives the current iterator value).
  6. The ORDER BY clause must sort by the iterator column.
  7. A LIMIT clause is recommended to bound memory usage per iteration.

Example — reads 10 rows per iteration, sorted by ts (the iterator column):

SELECT bool_v, str_v, dbl_v, long_v, entity_id, ts
FROM ts_kv
WHERE ts > ?
ORDER BY ts ASC
LIMIT 10

After each iteration the connector records the ts value of the last row and uses it as the ? placeholder in the next WHERE ts > ? call.

Required. Defines which column drives iteration, what its initial value is, and whether to persist the iterator position between gateway restarts.

Parameter Default Description
column Database column used to iterate through the result set
value Initial value of the iterator (mutually exclusive with query)
query SQL query that evaluates the initial iterator value (mutually exclusive with value)
save false Persist the iterator position between gateway restarts

How persistence works:

When save is true, the connector saves the iterator state to a file in config/odbc/ after each polling iteration. The file name is derived from a hash of:

  • ODBC driver name
  • Database server name
  • Database name
  • Iterator column name

On startup the connector looks for this file. If found, it restores the saved position; otherwise it uses value or query from the configuration file.

Required. Defines how columns from the query result set are mapped to ThingsBoard device names, attributes, and time-series values.

Parameter Default Description
device Device identification — see below
sendDataOnlyOnChange false Send data only when its value has changed since the last poll
attributes List of attribute columns or "*" for all columns
timeseries List of time-series columns or "*" for all columns

Required. Maps each result-set row to a unique ThingsBoard device name.

Parameter Default Description
name Python eval() expression that produces a unique device name
type odbc ThingsBoard device type

All columns listed in the SELECT clause are available by their column name inside the eval() expression. For example:

"device": {
"name": "'ODBC ' + entity_id"
}

This concatenates the string ODBC with the value of the entity_id column to form the device name (e.g. ODBC 1a2b3c).

Subsections “attributes” and “timeseries”

Section titled “Subsections “attributes” and “timeseries””

Both subsections support four configuration modes that can be mixed in a single array (combining mode).

Column name list — treat the listed column values directly as attribute/telemetry values:

"timeseries": [ "str_v", "ts" ]

Configuration list — rename columns and/or compute values with Python eval() expressions:

"timeseries": [
{
"name": "boolValue",
"column": "bool_v"
},
{
"nameExpression": "key_name",
"value": "[i for i in [str_v, long_v, dbl_v, bool_v] if i is not None][0]"
},
{
"name": "value",
"value": "[i for i in [str_v, long_v, dbl_v, bool_v] if i is not None][0]"
}
]
Parameter Description
name Fixed alias name for the key in ThingsBoard
nameExpression Python eval() expression that produces the key name dynamically
column Source column name (when key name differs from column name)
value Python eval() expression that computes the value

All SELECT columns are available by name in eval() expressions.

Combining mode — mix plain column names and configuration objects in the same array:

"timeseries": [
"ts",
{
"name": "value",
"value": "[i for i in [str_v, long_v, dbl_v, bool_v] if i is not None][0]"
}
]

Globbing — treat every column in the result set as a telemetry or attribute key:

"timeseries": "*"

The connector can call SQL stored procedures or functions when an RPC command is received from ThingsBoard. Parameters are taken from the connector configuration or from the RPC request payload.

Parameter Default Description
enableUnknownRpc false Process RPC commands that are not listed in methods
overrideRpcConfig false Allow the RPC payload to override procedure parameters defined in methods
methods List of RPC method configurations

The methods list supports three configuration modes:

Name-only list — calls procedures by name with no static arguments:

"methods": [ "procedureOne", "procedureTwo" ]

Configuration list — each entry specifies the RPC method name, optional static arguments, and an optional custom SQL query:

"methods": [
{
"name": "rpcProcOne",
"args": [ "One", 2, 3.0 ],
"query": "CALL procedureOne(?,?,?)"
},
{
"name": "functionOne",
"args": [ false ]
}
]
Parameter Default Description
name RPC method name (also used as the SQL procedure/function name if query is omitted)
query Custom SQL statement to call the procedure/function
args Static arguments passed to the procedure/function
result false SQL functions only. When true, the connector forwards the function return value to ThingsBoard; otherwise it returns success or failure

Combining mode — mix plain names and configuration objects:

"methods": [
"procedureOne",
{
"name": "procedureTwo",
"args": [ "One", 2, 3.0 ]
}
]

Dynamic RPC parameters:

When enableUnknownRpc is true, the RPC payload must include all required procedure parameters. When overrideRpcConfig is true, the payload may include any subset of parameters to override those in the configuration file. Example RPC payload:

{
"device": "ODBC Device 1",
"data": {
"method": "procedureOne",
"params": {
"args": [ "OverridedValue", 123, 3.14 ]
}
}
}