All Products
Search
Document Center

AnalyticDB:Access MySQL data using mysql_fdw

Last Updated:Mar 30, 2026

The mysql_fdw extension lets you query, insert, update, and delete data in a remote MySQL database directly from AnalyticDB for PostgreSQL — without copying data into AnalyticDB for PostgreSQL first.

How it works

mysql_fdw implements the PostgreSQL foreign data wrapper (FDW) interface. You define a foreign server pointing to your MySQL instance, map a database user to MySQL credentials, and then create foreign tables that mirror MySQL tables. Queries on those foreign tables are forwarded to MySQL, and several clause types (WHERE, JOIN, aggregate, ORDER BY, LIMIT/OFFSET) are pushed down to MySQL for execution to minimize data transfer.

Before you begin

Connect to a MySQL database

The setup requires three SQL statements run in sequence: CREATE SERVER, CREATE USER MAPPING, and CREATE FOREIGN TABLE (or IMPORT FOREIGN SCHEMA).

Step 1: Log in to your AnalyticDB for PostgreSQL instance

  1. Go to the AnalyticDB for PostgreSQL console and click the instance ID.

  2. In the upper-right corner, click Log On to Database.

  3. In the Log On to Database Instance dialog box, enter your Database Account and Database Password, then click Login.

Step 2: Create a foreign server

Run CREATE SERVER to define the remote MySQL database as a foreign server:

-- Create a foreign server named mysql_svr
CREATE SERVER mysql_svr
  FOREIGN DATA WRAPPER mysql_fdw
  OPTIONS (host '127.0.0.1', port '3306');

Expected output:

CREATE SERVER

Replace 127.0.0.1 and 3306 with your MySQL host and port. For all available options, see CREATE SERVER.

Step 3: Create a user mapping

Run CREATE USER MAPPING to associate an AnalyticDB for PostgreSQL user with MySQL credentials:

-- Map the public role to MySQL credentials
CREATE USER MAPPING FOR public
  SERVER mysql_svr
  OPTIONS (username '$MYSQL_USER_NAME', password '$MYSQL_PASS');

Expected output:

CREATE USER MAPPING

Replace $MYSQL_USER_NAME and $MYSQL_PASS with actual MySQL credentials.

Step 4: Create a foreign table

Run CREATE FOREIGN TABLE to define a local table that maps to a MySQL table. Column names must match the MySQL table's column names exactly.

-- Create a foreign table mirroring the MySQL table test_foreign_table
CREATE FOREIGN TABLE test_foreign_table (
  c1 INT,
  c2 INT,
  c3 TEXT,
  c4 TEXT
)
SERVER mysql_svr
OPTIONS (dbname 'mysql_fdw_database', table_name 'test_foreign_table');

Expected output:

CREATE FOREIGN TABLE

Alternatively, use IMPORT FOREIGN SCHEMA to create foreign tables automatically for all tables in a MySQL schema:

IMPORT FOREIGN SCHEMA mysql_fdw_database
  FROM SERVER mysql_svr
  INTO public;

Use LIMIT TO (table1, table2) to import only specific tables, or EXCEPT (table1, table2) to import all tables except the listed ones. For all available options, see IMPORT FOREIGN SCHEMA.

Step 5: Query and modify data

After the foreign table is created, run SELECT, INSERT, UPDATE, and DELETE on it as you would on any local table:

-- Query data
SELECT * FROM test_foreign_table;

-- Insert a row
INSERT INTO test_foreign_table (c1, c2, c3, c4) VALUES (1, 2, 'foo', 'bar');

-- Update a row
UPDATE test_foreign_table SET c3 = 'updated' WHERE c1 = 1;

-- Delete a row
DELETE FROM test_foreign_table WHERE c1 = 1;
For INSERT, UPDATE, and DELETE to work, the MySQL source table must use its first column as the unique primary key column or as part of a composite primary key. This constraint does not apply to SELECT.

Usage notes

  • DML primary key requirement: For UPDATE, DELETE, and INSERT operations, the MySQL source table must use its first column as the unique primary key or as part of a composite primary key. SELECT is not subject to this constraint.

  • Connection pool: All queries in the same session reuse the same MySQL connection rather than creating a new one per query.

  • NULL sort order: MySQL sorts NULL values differently from AnalyticDB for PostgreSQL. When using ORDER BY pushdown, add an IS NULL predicate at the start of each ORDER BY clause so that MySQL places NULLs at the end of ascending result sets, matching AnalyticDB for PostgreSQL behavior.

Syntax reference

CREATE SERVER

CREATE SERVER [IF NOT EXISTS] server_name [TYPE 'server_type'] [VERSION 'server_version']
  FOREIGN DATA WRAPPER fdw_name
  [OPTIONS ([mpp_execute 'any | master | all segments'], option 'value' [, ...])]

Options

Option Type Description Default
host string IP address or hostname of the MySQL database 127.0.0.1
port integer Port number of the MySQL database 3306
init_command string SQL statement run when the connection is established Empty
secure_auth boolean Whether to use MySQL's pre-V5.7.5 password() encryption method true
use_remote_estimate boolean Whether to run EXPLAIN on MySQL to collect table statistics for query planning false
reconnect boolean Whether to allow automatic reconnection false
character_set string Character set for the connection. auto detects the character set from the MySQL client OS auto
sql_mode string SQL mode in MySQL, which affects SQL syntax and data validation. See Server SQL Modes ANSI_QUOTES
ssl_key string Path to the private key file on the MySQL client Empty
ssl_cert string Path to the public key certificate on the MySQL client Empty
ssl_ca string Path to the CA certificate. If specified, the foreign server uses the same certificate Empty
ssl_capath string Path to a directory containing trusted SSL CA certificates Empty
ssl_cipher string SSL cipher suites allowed for encryption <none>
fetch_size integer Number of rows fetched per execution. A value set on the foreign table overrides this server-level value 100

CREATE USER MAPPING

CREATE USER MAPPING [IF NOT EXISTS] FOR { user_name | USER | CURRENT_USER | PUBLIC }
  SERVER server_name
  [OPTIONS (option 'value' [, ...])]

Options

Option Type Description Default
username string Username for the MySQL database Empty
password string Password for the MySQL database Empty

CREATE FOREIGN TABLE

CREATE FOREIGN TABLE [IF NOT EXISTS] table_name ([
  { column_name data_type [OPTIONS (option 'value' [, ...])] [COLLATE collation] [column_constraint [...]]
    | table_constraint }
  [, ...]
])
[INHERITS (parent_table [, ...])]
  SERVER server_name
[OPTIONS ([mpp_execute 'any | master | all segments'], option 'value' [, ...])]

Options

Option Type Description Default
dbname string Name of the MySQL database containing the table Empty
table_name string Name of the MySQL table to map to A custom name in AnalyticDB for PostgreSQL
fetch_size integer Number of rows fetched per execution. Overrides the server-level fetch_size 100

IMPORT FOREIGN SCHEMA

Use IMPORT FOREIGN SCHEMA to create foreign tables automatically for MySQL tables, instead of defining each with CREATE FOREIGN TABLE.

IMPORT FOREIGN SCHEMA remote_schema
  [{ LIMIT TO | EXCEPT } (table_name [, ...])]
  FROM SERVER server_name
  INTO local_schema
  [OPTIONS (option 'value' [, ...])]
  • LIMIT TO (table_name, ...): import only the listed tables.

  • EXCEPT (table_name, ...): import all tables except the listed ones.

Options

Option Type Description Default
import_default boolean Whether to include column DEFAULT expressions when creating foreign tables FALSE
import_not_null boolean Whether to include column NOT NULL constraints when creating foreign tables TRUE
import_enum_as_text boolean Whether to map MySQL ENUM columns to TEXT. If FALSE, the system prompts you to create the ENUM type manually FALSE

Performance features

mysql_fdw pushes several clause types down to MySQL for execution, reducing data transferred to AnalyticDB for PostgreSQL.

Feature Description
Connection pool All queries in the same session share one MySQL connection.
WHERE pushdown WHERE conditions on foreign tables are evaluated in MySQL, so only matching rows are returned.
Projection pushdown Only the columns referenced in SELECT are fetched from MySQL, not the full row.
Prepared statement SELECT queries use prepared statements for better performance.
JOIN pushdown JOIN operations between two foreign tables in the same MySQL database run in MySQL. Supported join types: INNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN. Not supported: FULL OUTER JOIN, SEMI JOIN, ANTI JOIN. Only JOINs with relational and arithmetic operators are pushed down.
Aggregate pushdown Aggregate functions (MIN, MAX, SUM, AVG, COUNT) run in MySQL.
ORDER BY pushdown ORDER BY clauses run in MySQL to return an ordered result set. Add an IS NULL predicate before each ORDER BY column to handle NULL sort order differences between MySQL and AnalyticDB for PostgreSQL.
LIMIT and OFFSET pushdown LIMIT and OFFSET clauses run in MySQL, reducing data transferred.

Compatibility

ApsaraDB RDS for MySQL

Version Compatible
5.5 Yes
5.6 Yes
5.7 Yes
8.0 Yes

Self-managed MySQL database

MySQL versions earlier than 5.7 are no longer maintained. MySQL 5.7 and 8.0 are in common use.

Version Compatible
5.7 Yes
8.0 (mainly used) Yes

PolarDB for MySQL

Version Compatible
5.6 Yes
5.7 Yes
8.0.1 Yes
8.0.2 Yes

Data type mapping

No. MySQL data type AnalyticDB for PostgreSQL data type
1 BIT(N) BIT(N)
2 TINYINT SMALLINT
3 TINYINT UNSIGNED SMALLINT
4 SMALLINT SMALLINT
5 SMALLINT UNSIGNED BIGINT
6 MEDIUMINT INT
7 MEDIUMINT UNSIGNED INT
8 INT INT
9 INT UNSIGNED BIGINT
10 BIGINT BIGINT
11 BIGINT UNSIGNED NUMERIC
12 DECIMAL(M,N) NUMERIC
13 FLOAT REAL
14 DOUBLE(M,N) DOUBLE PRECISION
15 DATE DATE
16 DATETIME DATETIME without TIME zone
17 TIMESTAMP DATETIME without TIME zone
18 TIME TIME without TIME zone
19 YEAR[4] Not supported
20 CHAR[N] CHAR[N]
21 VARCHAR[N] CHARACTER VARYING(N)
22 BINARY[N] BYTEA
23 VARBINARY[N] BYTEA
24 TINYBLOB Not supported
25 TINYTEXT TEXT
26 BLOB BYTEA
27 TEXT TEXT
28 MEDIUMBLOB BYTEA
29 MEDIUMTEXT TEXT
30 LONGBLOB BYTEA
31 LONGTEXT TEXT
32 ENUM(",") Prompted to manually create data of the ENUM type
33 SET('','') Not supported
34 GEOMETRY Not supported
35 POINT POINT
36 LINESTRING Not supported
37 POLYGON POLYGON
38 MULTIPOINT Not supported
39 MULTILINESTRING Not supported
40 MULTIPOLYGON Not supported
41 GEOMETRCOLLECTION Not supported
42 JSON JSON

What's next