Disclosure: Navicat gave me free Premium access for this review and offered a one-year Premium subscription (about US$1,000) if I published. Navicat did not see or approve this text, and told me the review did not have to be positive.
I tested Navicat Premium 18 (AppImage) on Ubuntu against four engines: a local Postgres 16 container, a SQLite file, an Oracle Autonomous Database on Oracle Cloud's Always Free tier (Oracle AI Database 26ai), and a MySQL HeatWave database on the same cloud. Everything used invented finance-style data. I include the SQL and the setup commands, so you can repeat each test.
The short version
- Worked well: Postgres to Postgres transfer and synchronization, with the exact SQL shown before anything ran. Oracle to Oracle transfer, structure sync and data sync also worked. On MySQL HeatWave, Data Transfer, Structure Synchronization, Data Synchronization and Data Masking all finished with 0 errors.
- Needed manual checks: Postgres to SQLite lost auto-numbering and defaults. Postgres to MySQL kept the keys and the foreign key but turned
SERIALinto a plainintand dropped thenow()default. Postgres to Oracle mapped timestamps toDATE. Thecustomerstransfer failed when Navicat's generatedTO_DATEexpression received fractional seconds its format did not allow, and trimming the source timestamps to whole seconds got those rows through. - Rough edges on Linux: connecting to an Autonomous Database took a wallet, Oracle Instant Client and a
libaiolink, and the Net Service Name dropdown stayed empty. The SSH tunnel to MySQL HeatWave showed a key passphrase prompt although my key has none. - AI features: they work with a model you bring, and the results depend on it. I used a free Nvidia model through OpenRouter.
- Not tested: real or large data, other platforms and stronger AI models.
What I tested and how
- When and where: November 2026, with Navicat Premium 18 as an AppImage on Ubuntu.
- Data: a
customerstable (8 rows, with name, email, phone, national ID and county) and atransactionstable (200 rows, with amounts in KES). Larger copies,customers_ai(about 1,000 generated rows) andtransactions_ai(200 rows), were used for the AI and transfer tests. - Everything was fake. Nothing real went through Navicat or through any AI provider.
- AI model: a free Nvidia Nemotron model reached through OpenRouter. Frontier models such as Claude from Anthropic, Kimi from Moonshot and GPT from OpenAI typically need API keys and may incur usage charges, which is why I chose a free one. It is not a model Navicat bundles, so anything below about AI output reflects that choice.
Data Masking
Data Masking lives under Tools and worked on Postgres, but partial masking keeps fragments of the original, so choose techniques by risk.
I picked a technique for each column from a dropdown. Most of my choices produced partial masking: asterisks replace most characters while the format stays realistic.
| Column | What the output looked like | What still leaks |
|---|---|---|
full_name | A**** W******* | initial letters and name length |
email | a*****w@e**********m | first and last character of the local part, last character of the domain |
phone | +25******0001 | country prefix and last 4 digits |
national_id | 1******* on one copy, NULL on another | one digit when partial, nothing when nulled |
county, customer_id, created_at | left unmasked on purpose | not applicable |
I left customer_id alone because masking a key would break the link to transactions. Nulling the national ID was the safest result, but it only works on columns that allow NULL, so it would fail on full_name. Partial masking is fine for stopping casual viewing in test data. For anything that must resist re-identification, use a substitution technique or null the column.
Queries I used for the masking test
The masked output went into a copy of customers called customers_ai, so I could compare it with the original. I first created the copy with AS TABLE, which copies the columns and rows but not the keys or defaults, then dropped it and used LIKE ... INCLUDING ALL, which copies the structure with its constraints, defaults and indexes but no rows.
CREATE TABLE customers_ai AS TABLE customers; DROP TABLE customers_ai; CREATE TABLE customers_ai (LIKE customers INCLUDING ALL); To see what each technique did, I joined the original and masked tables side by side:
SELECT o.customer_id, o.full_name AS original_name, m.full_name AS masked_name, o.email AS original_email, m.email AS masked_email FROM customers o JOIN customers_ai m USING (customer_id); For the AI tests I wanted realistic names again, so I replaced the masked names in customers_ai by cycling through a list of 20 invented Kenyan names:
UPDATE customers_ai ai SET full_name = np.full_name FROM ( SELECT customer_id, row_number() OVER (ORDER BY customer_id) AS rn FROM customers_ai ) t JOIN ( SELECT full_name, row_number() OVER () AS rn, count(*) OVER () AS total FROM (VALUES ('Wanjiku Kamau'), ('Otieno Odhiambo'), ('Njeri Mwangi'), ('Mwende Mutiso'), ('Akinyi Odongo'), ('Muthoni Karuki'), ('Kibet Rotich'), ('Atieno Achieng'), ('Maina Njoroge'), ('Wekesa Barasa'), ('Nafula Wanjala'), ('Kamau Ndungu'), ('Achieng Ouko'), ('Mutuku Kilonzo'), ('Wambui Githinji'), ('Odhiambo Onyango'), ('Nduta Kimani'), ('Korir Ruto'), ('Auma Otieno'), ('Chepkorir Langat') ) AS v(full_name) ) np ON np.rn = ((t.rn - 1) % np.total) + 1 WHERE ai.customer_id = t.customer_id; SELECT customer_id, full_name FROM customers_ai ORDER BY customer_id LIMIT 10; The VALUES list has no explicit numbering, so Postgres does not guarantee the order in which the names are cycled. Give each name an explicit number if you need a reproducible result.
Postgres to Postgres: generation, transfer and synchronization
Between two Postgres databases (my_project_db as the source and my_target_db as the target), Navicat copied and synced my data correctly and showed the exact SQL before running anything.
- Data Generation: produced about 1,000 rows, and Navicat reported 0.00186 seconds for it.
- Data Transfer: I copied
customers,customers_ai,transactionsand the two sequences behind theSERIALcolumns into the second database. Row counts matched, with 200 rows intransactionson both sides. - Data Synchronization: after I changed one county in the source, the comparison found exactly one row to update and nothing to insert or delete. It listed
customers(8 rows) andtransactions(200 rows) as identical. After running it, the changed value appeared in the target. - Structure Synchronization: it flagged the
risk_scorecolumn I had added and showed theALTER TABLEscript before applying it.
Two cautions from the previews:
- The data sync script updated every column of the changed row, not only the county. On a busy table, that could overwrite someone else's recent edit to another column.
- Sync copies whatever the source holds, including masked values. Mask before you sync to a test environment, not after.
A Recompare button and a per-table tick box made it easy to check and limit what would run.
Queries I used on these tests
The first two statements built the _ai copy of transactions. The next two checked the transfer on both sides. The ALTER TABLE is the schema change I used for Structure Synchronization, and the last query reads the county of the row I changed for Data Synchronization.
CREATE TABLE transactions_ai (LIKE transactions INCLUDING ALL); INSERT INTO transactions_ai SELECT * FROM transactions; SELECT count(*) FROM transactions; SELECT round(sum(amount_kes), 2) FROM transactions; ALTER TABLE customers_ai ADD COLUMN risk_score INT; SELECT county FROM customers_ai WHERE customer_id = 1002; Postgres to SQLite
The data and keys survived a move to a different engine, but auto-increment and column defaults did not, so check them by hand after any cross-engine transfer.
I transferred the tables from Postgres into a new SQLite file with Data Transfer, leaving the sequences unticked because SQLite has none.
| Check | Result |
|---|---|
| Row counts | Matched |
Sum of amount_kes over 200 rows | 5121876.44 in both engines |
Primary key on customer_id | Kept |
NOT NULL on customer_id and full_name | Kept |
Foreign key from transactions to customers | Kept |
Auto-numbering on customer_id | Lost |
Default on created_at | Lost |
| Types | int4 became integer(32), varchar(n) became text(n), timestamps became text(6) |
The lost auto-numbering showed up as soon as I inserted a row without an id: SQLite rejected it with a NOT NULL constraint failure. I suspect the cause is that the column arrived as integer(32) and not as a plain INTEGER PRIMARY KEY, which is the form SQLite fills in itself, but I did not confirm that.
Queries I used on the SQLite copy
SELECT round(sum(amount_kes), 2) FROM transactions; SELECT count(*) FROM transactions; PRAGMA table_info(customers); PRAGMA foreign_key_list(transactions); SELECT sql FROM sqlite_master WHERE name = 'customers'; SELECT * FROM customers LIMIT 3; SELECT customer_id FROM customers ORDER BY customer_id DESC LIMIT 1; When I asked the AI to correct the failed insert, it declined to guess. Its reply was a comment saying it could not safely correct the statement, because customers.customer_id is NOT NULL and the insert supplied no value or default, and it asked for the table schema or a valid customer_id.
Postgres to Oracle Autonomous Database
Oracle was the hardest test: getting connected took real work on Linux, and the transfer failed on timestamps until I changed the source data.
Connecting from Linux
An Autonomous Database needs a downloaded wallet and an Oracle client library, so the setup is more than a hostname and password. These are the commands that got me connected, in the order that worked. Replace <your_db> with your database name, and run steps 4 to 6 in one terminal so the IC variable stays set.
Step 1. Check whether an Instant Client is already on the machine.
find ~ /opt /usr/lib -name 'libclntsh.so*' 2>/dev/null Step 2. Unzip the Instant Client. I used the 23.26 Basic zip (about 137 MB) from Oracle's download page.
mkdir -p ~/oracle unzip -q ~/Downloads/instantclient-basic-linux.x64-23.26.4.0.0.zip -d ~/oracle ls -l ~/oracle/instantclient_23_26/libclntsh.so* Step 3. Unzip the wallet you downloaded from the Oracle Cloud console.
mkdir -p ~/network/admin unzip ~/Downloads/Wallet_<your_db>.zip -d ~/network/admin Step 4. Point the wallet's sqlnet.ora at a real path, and copy the wallet into the Instant Client.
IC=~/oracle/instantclient_23_26 sed -i "s|DIRECTORY=\"[^\"]*\"|DIRECTORY=\"$HOME/network/admin\"|" ~/network/admin/sqlnet.ora mkdir -p $IC/network/admin cp ~/network/admin/* $IC/network/admin/ sed -i "s|DIRECTORY=\"[^\"]*\"|DIRECTORY=\"$IC/network/admin\"|" $IC/network/admin/sqlnet.ora cat -A ~/network/admin/sqlnet.ora cat -A $IC/network/admin/sqlnet.ora Each file should hold two lines: the WALLET_LOCATION line with your path, and SSL_SERVER_DN_MATCH=yes. One of my copies lost the second line, so if yours is missing it, add it back:
printf '\nSSL_SERVER_DN_MATCH=yes\n' >> ~/network/admin/sqlnet.ora Step 5. Ask Linux which libraries the client cannot find.
ldd $IC/libclntsh.so.23.1 | grep "not found" Mine listed libnnz.so, libaio.so.1 and libclntshcore.so.23.1. The first and last live in the Instant Client folder itself, and libaio needs a link because Ubuntu names it libaio.so.1t64.
Step 6. Register the folder, link libaio, and check again.
echo $IC | sudo tee /etc/ld.so.conf.d/oracle-instantclient.conf sudo ldconfig sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 ldd $IC/libclntsh.so.23.1 | grep "not found" The last command should print nothing. A link placed inside the Instant Client folder did not work for libaio, because ldconfig ignores it there.
Step 7. List the service names in the wallet.
grep -oE '^[A-Za-z0-9_]+ *=' $IC/network/admin/tnsnames.ora You should see five aliases ending in _high, _medium, _low, _tp and _tpurgent.
Step 8. Set up Navicat.
- In Tools > Options > Environment, set the OCI library to
/home/<you>/oracle/instantclient_23_26/libclntsh.so. Leave "Use bundled OCI library" unticked, then quit Navicat completely and reopen it. - Create an Oracle connection with Connection Type TNS, type the Net Service Name by hand (I used the
_lowalias), enter your user, and type the password yourself. - Click Test Connection.
Two things confused me. The Net Service Name dropdown stayed empty even though tnsnames.ora was valid, but typing the alias by hand worked, and Navicat then filled in the full Service Name itself. And with no alias set, the error was ORA-12547 (lost contact), which says nothing about a missing service name. A later ORA-01017 simply meant the password I typed did not match the one stored in the database, so check that before blaming the wallet.
Also worth knowing for a trial: Always Free databases stop after 7 days of inactivity and need a manual Start in the Oracle console. Oracle's documentation also says a database that is stopped and stays inactive for 90 days, cumulative, may be reclaimed and permanently deleted, so start it again before then if you want to keep it.
Creating the test user
I ran this in Database Actions as ADMIN. Choose your own password, 12 to 30 characters with an upper-case letter, a lower-case letter and a digit, and type it without the angle brackets. My first attempt kept the brackets as part of the password, and every login then failed with ORA-01017.
CREATE USER navicat_test IDENTIFIED BY "<your password>"; GRANT DWROLE TO navicat_test; ALTER USER navicat_test QUOTA UNLIMITED ON DATA; To change the password later:
ALTER USER navicat_test IDENTIFIED BY "<new password>"; To check the account and the session from ADMIN:
SELECT username, account_status, authentication_type FROM dba_users WHERE username = 'NAVICAT_TEST'; SELECT granted_role FROM dba_role_privs WHERE grantee = 'NAVICAT_TEST'; SELECT SYS_CONTEXT('USERENV', 'SESSION_USER') FROM dual; After I edited a duplicated connection to use navicat_test, an open query tab still returned ADMIN. Navicat keeps the old session alive, so close the tab and the connection, then reopen the connection.
What the transfer showed
I transferred four tables from Postgres into the new schema. The final row counts matched the source, but only after the timestamp problem below.
| Check | Result |
|---|---|
| Row counts | customers 8, customers_ai 1000, transactions 200, transactions_ai 200, matching Postgres |
Sum of amount_kes on transactions | 5121876.44 in Oracle and in Postgres |
| Table names | created as quoted lower-case names, so queries need "customers" in double quotes |
| Integers | integer became NUMBER(11) |
| Text | varchar(n) became NVARCHAR2(n) |
| Money | numeric(12,2) became plain NUMBER, so the precision and scale were dropped |
| Timestamps | timestamp became DATE |
| Auto-numbering and defaults | the generated CREATE TABLE had no identity column and no defaults |
I only compared the amount sum for transactions, not for transactions_ai.
Queries I used to check the transfer
On Oracle, as navicat_test:
SELECT 'customers' AS tbl, COUNT(*) AS n FROM "customers" UNION ALL SELECT 'customers_ai', COUNT(*) FROM "customers_ai" UNION ALL SELECT 'transactions', COUNT(*) FROM "transactions" UNION ALL SELECT 'transactions_ai', COUNT(*) FROM "transactions_ai"; SELECT COUNT(*), SUM("amount_kes") FROM "transactions"; SELECT table_name, column_name, data_type FROM user_tab_columns WHERE data_type = 'DATE' OR data_type LIKE 'TIMESTAMP%' ORDER BY table_name, column_name; On Postgres, for the source side:
SELECT 'customers' AS t, COUNT(*) FROM customers UNION ALL SELECT 'customers_ai', COUNT(*) FROM customers_ai UNION ALL SELECT 'transactions', COUNT(*) FROM transactions UNION ALL SELECT 'transactions_ai', COUNT(*) FROM transactions_ai; SELECT table_name, column_name, data_type, numeric_precision, numeric_scale, character_maximum_length FROM information_schema.columns WHERE table_schema = 'public' AND table_name IN ('customers','customers_ai','transactions','transactions_ai') ORDER BY table_name, ordinal_position; The timestamp failure
The first transfer loaded only transactions. For customers, Navicat generated inserts like this:
TO_DATE('2026-11-08 06:42:11.182712', 'SYYYY-MM-DD HH24:MI:SS') Oracle rejected the first row with ORA-01830, because the format stops at seconds while the value carries microseconds. The inserts ran as one block, so that single error rolled back all 8 rows. transactions loaded because its txn_date is a plain date with no fractional seconds. The other two tables showed as terminated, with no error text I could read.
The Data Transfer options matter here. By default it drops and recreates the target tables, so any column type I fixed by hand in Oracle was lost on the next run. With drop unticked and continue-on-error ticked, the run still attempted the create step and logged ORA-00955 (name already used), which is harmless. The TO_DATE error came back for customers on those runs.
I first tried changing the Oracle columns to hold fractional seconds. That alone did not get the customers rows through:
ALTER TABLE "customers" MODIFY ("created_at" TIMESTAMP(6)); ALTER TABLE "customers_ai" MODIFY ("created_at" TIMESTAMP(6)); What worked was giving Navicat different source data. Run this in a Postgres query tab, not an Oracle one (I ran it against Oracle by mistake first and got ORA-02420, because CREATE SCHEMA and date_trunc are Postgres syntax):
CREATE SCHEMA oracle_src; CREATE TABLE oracle_src.customers AS SELECT customer_id, full_name, email, phone, national_id, county, date_trunc('second', created_at) AS created_at FROM public.customers; In Data Transfer, I then set the source to oracle_src and ticked only customers. All 8 rows arrived. That means the microseconds were cut to whole seconds, which is a small loss of precision. customers_ai and transactions_ai loaded in full on the later runs, and I did not work out why customers_ai avoided the same error.
Keys
The Postgres source has a primary key on each of the four tables and one foreign key, from transactions to customers. This is how the keys turned out on Oracle, in order:
- First run: no primary or foreign keys on any Oracle table.
- Later run: the log shows Navicat adding keys as a separate
ALTER TABLE ... ADD CONSTRAINTstep after the data. That step failed with ORA-02260 (table can have only one primary key), which suggests a key was already there from an earlier run. - Final check from ADMIN:
customers,customers_aiandtransactions_aihad primary keys,transactionshad none, and none of the four tables had a foreign key. - Manual repair: I added the missing
transactionskey by hand before the synchronization tests below.
These are the queries I used to compare. user_constraints only lists the logged-in user's own constraints, so from ADMIN I used dba_constraints and filtered by owner:
-- Postgres SELECT conrelid::regclass AS tbl, conname, contype, pg_get_constraintdef(oid) AS def FROM pg_constraint WHERE connamespace = 'public'::regnamespace AND contype IN ('p','f') ORDER BY 1, 2; -- Oracle, as navicat_test SELECT table_name, constraint_name, constraint_type, r_constraint_name FROM user_constraints WHERE constraint_type IN ('P','R') ORDER BY table_name; -- Oracle, as ADMIN SELECT owner, table_name, constraint_name, constraint_type, status FROM dba_constraints WHERE owner IN ('NAVICAT_TEST', 'NAVICAT_TARGET') AND constraint_type IN ('P', 'R') ORDER BY owner, table_name, constraint_type; Data Masking on Oracle
I ran Navicat's Hashing technique on full_name in customers_ai. It failed with PLS-00927: bind variable 'full_name' was not used and ORA-03066: invalid PL/SQL expression, after about 68 seconds, so the SQL Navicat generated for Oracle was not valid. The same masking tool worked on Postgres earlier. I did not try the other masking techniques on Oracle, so I cannot say whether the problem is specific to Hashing.
Oracle to Oracle: generation and synchronization
Data Generation, Structure Synchronization and Data Synchronization all worked on Oracle. I compared two Oracle schemas for the synchronization tests, because Structure Synchronization offered only same-engine targets in my build.
Data Generation
Data Generation filled an Oracle table with 1000 rows and 0 errors, but it was far slower than the local Postgres run. Navicat reported 0.00186 seconds on Postgres. On Oracle the window showed 06:14.974, which I read as 6 minutes 15 seconds. The target is a cloud database reached from Nairobi, which is a likely factor, but I did not test that.
CREATE TABLE gen_test ( id NUMBER(11) NOT NULL, full_name VARCHAR2(100), county VARCHAR2(50), amount_kes NUMBER(12,2), created_at TIMESTAMP(6) ); I refreshed the tree, opened Data Generation on gen_test, and asked for 1000 rows. The log showed the run inside one transaction with a begin and a commit, then "Finished successfully". The TIMESTAMP(6) column generated without the date-format error that broke the transfer. Reading the rows back took 2.777 seconds:
SELECT COUNT(*) FROM gen_test; SELECT * FROM gen_test FETCH FIRST 5 ROWS ONLY; Setting up two Oracle schemas
Structure Synchronization only listed targets of the same engine as the source. With a Postgres source, the target side showed only Postgres, and with an Oracle source it showed only Oracle. Navicat's feature matrix labels only Data Transfer as working across server types, and lists the two synchronization tools without that label, which fits what I saw for Structure Synchronization. I did not check the target list for Data Synchronization.
So I built a second Oracle schema to compare against. In Database Actions as ADMIN, with your own password typed without the angle brackets:
CREATE USER navicat_target IDENTIFIED BY "<your password>"; GRANT DWROLE TO navicat_target; ALTER USER navicat_target QUOTA UNLIMITED ON DATA; I added a second connection, Oracle_navicat_target, with the same wallet and _low alias and the new user. Then I ran Data Transfer from Oracle_navicat_test to Oracle_navicat_target, ticking only transactions. It moved 200 records with 0 errors in 21.681 seconds. In the target, as navicat_target:
SELECT COUNT(*), SUM("amount_kes") FROM "transactions"; SELECT column_name, data_type, data_precision, data_scale FROM user_tab_columns WHERE LOWER(table_name) = 'transactions' ORDER BY column_id; SELECT constraint_name, constraint_type FROM user_constraints WHERE LOWER(table_name) = 'transactions'; The target held 200 rows and a sum of 5121876.44, matching the source. The columns came through as NUMBER(11,0), NUMBER, NVARCHAR2 and DATE, and the structure comparison later showed no differences in any of them. The constraint query returned only check constraints and no primary key.
Data Synchronization matches rows by key, so I added a primary key to the table in both schemas, once as navicat_test and once as navicat_target:
ALTER TABLE "transactions" ADD CONSTRAINT "transactions_pkey" PRIMARY KEY ("txn_id"); Structure Synchronization on Oracle
Structure Synchronization added the new column correctly, but Navicat pre-ticked two deletions on the target that I had to untick by hand. In the source I added a column:
ALTER TABLE "transactions" ADD ("channel" VARCHAR2(20)); I compared NAVICAT_TEST (source) with NAVICAT_TARGET (target). The screen listed one table to modify, transactions, and four to create, which were the tables that exist only in the source. I ticked none of the four. Inside transactions, Navicat showed channel as an addition. It also pre-ticked two red-X rows that would drop two system-named check constraints found only on the target, so I unticked them and left only channel.
The Deployment Script tab stayed empty until I clicked Next, which was confusing. The script then read:
ALTER TABLE "NAVICAT_TARGET"."transactions" ADD ("channel" VARCHAR2(20 BYTE) VISIBLE) The run reported 1 of 1 successful, 0 errors, 0.718 seconds. I confirmed the column in the target:
SELECT column_name, data_type, data_length FROM user_tab_columns WHERE LOWER(table_name) = 'transactions' AND LOWER(column_name) = 'channel'; It returned channel, VARCHAR2, 20.
Data Synchronization on Oracle
Data Synchronization found exactly the one row I changed and applied it correctly. In the source:
UPDATE "transactions" SET "txn_type" = 'sync_test' WHERE "txn_id" = 1; COMMIT; The comparison for transactions showed 0 to insert, 1 to update, 0 to delete and 199 identical. I ran it, then checked the target:
SELECT "txn_id", "txn_type" FROM "transactions" WHERE "txn_id" = 1; SELECT COUNT(*), SUM("amount_kes") FROM "transactions"; The row showed sync_test, the count was still 200 and the sum was still 5121876.44. I added the primary key on both sides before comparing, so I did not test what Navicat does without one.
Postgres to MySQL HeatWave on Oracle Cloud
MySQL HeatWave sits in a private network, so I reached it through a small jump host and Navicat's SSH tunnel. Once connected, Data Transfer, Structure Synchronization, Data Synchronization and Data Masking all finished with 0 errors. The transfer kept the primary keys and the foreign key, but it turned the SERIAL columns into plain integers and dropped the now() default.
Setting up MySQL HeatWave and a jump host
Each Oracle Cloud tenancy can have one Always Free MySQL HeatWave DB system in its home region (Oracle docs). It is a 1 ECPU MySQL node with 50 GB of storage and 50 GB of backup storage (Oracle announcement). It can also have a free single-node HeatWave cluster, which none of my tests used. The free VM options are two AMD micro instances with 1/8 OCPU and 1 GB of memory each, plus Ampere Arm instances (Oracle docs). Pick the option labelled Always Free or Always Free-eligible in each form, because other shapes are billed by the hour. These are the Always Free limits in Oracle's documentation when I tested, so check the current limits and your eligibility in your own tenancy before you create anything.
The database has no public IP address, so the path from your laptop is: Navicat, SSH on port 22 to a jump host in the public subnet, then TCP 3306 to the database in the private subnet. Values in angle brackets below are placeholders for your own.
- Create the network. In the OCI console open Virtual Cloud Networks and start the VCN Wizard. Choose "Create VCN with Internet Connectivity", name it
<VCN_NAME>and keep the default ranges: VCN10.0.0.0/16, public subnet10.0.0.0/24, private subnet10.0.1.0/24. - Let the public subnet reach MySQL. Open the private subnet, then its security list, and add an ingress rule: stateful, source type CIDR, source
10.0.0.0/24, protocol TCP, destination port 3306. This allows the whole public subnet, which is what I used for my throwaway test. Once the jump host exists (step 4), it is safer to replace the source with the jump host's private IP followed by/32, which its Details page shows. - Create the DB system.Source:https://dev.to/derrickryangiggs/navicat-premium-18-on-linux-a-hands-on-review-with-postgres-sqlite-oracle-and-mysql-4a42