- Error code
- ORA-00911
- Product
- Oracle Database
- Versions
- Oracle Database 19c, 21c, 23ai and 26ai (wording differs: see below)
- Category
- SQL Syntax & Query Structure
- Last reviewed
- 24 October 2026
On this page
What it means
ORA-00911 means the SQL text contains a character Oracle does not allow at that point, such as a symbol inside an unquoted name, a stray semicolon sent by application code, or a typographic quote pasted from a document.
An unquoted Oracle identifier may contain only letters, digits and the characters $, _ and #, and those three may not come first. Any other character (a hyphen, a tilde, a space, an @) is only allowed inside a name written in double quotes. Oracle's current reference shows the case directly: SELECT user~id FROM users fails, while SELECT "user~id" FROM users is valid. Current releases name the invalid character and the token before it in the message; 19c and 21c print just "invalid character".
Not every ORA-00911 is about names. A semicolon ends a statement in SQL*Plus, SQLcl and SQL Developer scripts, but it is not part of the SQL statement itself, so a semicolon sent through JDBC, ODBC, Python or another driver at the end of a single statement can be rejected as an invalid character. Characters that look normal but are not plain ASCII, such as curly quotes from a word processor or a non-breaking space, cause the same error. For passwords, Oracle's reference recommends always enclosing the password in double quotation marks in the IDENTIFIED BY clause of CREATE USER and ALTER USER.
Common causes
- An unquoted name contains a character Oracle does not allow, such as a hyphen, tilde or space, or begins with $, _ or #.
- Application code sends a statement with a trailing semicolon through a driver (JDBC, ODBC, Python, .NET).
- Curly quotes, a non-breaking space or another non-ASCII character was pasted into the statement from a document, chat or web page.
- A password with special characters is written without double quotes in CREATE USER or ALTER USER ... IDENTIFIED BY.
- An alternative-quoting literal (q'#...#') uses a space, tab or carriage return as its delimiter, which Oracle's 19c reference says is not allowed.
Diagnose it
Read-only These queries only read the data dictionary (USER_, ALL_ and DBA_ views) and dynamic performance views (V$). They do not change data, privileges or settings, so they are safe to run first. DBA_ and V$ views need the matching privileges.
Find the character Oracle marks
In current releases the message itself names the character and the token before it. On 19c, use the asterisk in SQL*Plus or SQLcl, or the line and column your tool reports. Retype that part of the statement by hand rather than copying it again.
Look for hidden non-ASCII characters
Paste the statement into an editor that can show invisible characters, or search it for curly quotes and non-breaking spaces. In code, log the exact SQL string (with its length) just before it is executed, so a trailing semicolon or an odd character is visible.
Check how an awkward name is stored
If the column or table really has special characters in its name, the dictionary shows the exact spelling to put in double quotes.
SELECT table_name, column_name
FROM user_tab_columns
WHERE REGEXP_LIKE(column_name, '[^A-Z0-9_$#]')
ORDER BY table_name, column_name; Columns whose names contain characters outside the plain upper-case set; each must be written in double quotes with exactly this spelling.
How to fix it
Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.
Quote names that contain special characters (or rename them)
Read-onlyOracle's documented fix: enclose such an identifier in double quotation marks, matching its exact case. In new designs, use plain names (user_id rather than user-id) so quotes are never needed.
SELECT "user~id"
FROM users;
Drop the trailing semicolon when executing from code
Client or network sidePass a single SQL statement to the driver without the terminating semicolon. A PL/SQL block is different: it ends with END; and keeps that semicolon, because it is part of the block. The "/" line used in SQL*Plus scripts is never sent.
-- in application code, send exactly this text:
SELECT id, email FROM shop.customers WHERE id = :id
Replace typographic characters with plain ones
Client or network sideReplace curly quotes with straight single quotes for strings and straight double quotes for identifiers, and replace non-breaking spaces with ordinary spaces. Copy SQL from plain-text sources, not from formatted documents.
Put passwords with special characters in double quotes
Changes permissionsAs Oracle's reference recommends, always enclose the password in double quotation marks in IDENTIFIED BY; any character other than the double quote is then allowed.
Caution: Changing a password breaks every application and job that still uses the old one. Use a real secret from your password manager rather than the example, and update the connection settings at the same time.
ALTER USER report_app IDENTIFIED BY "Str0ng#Pass-2026";
Examples
A symbol in an unquoted column name
Not reproduced here: no Oracle Database is installed for this site. The statement is the example from Oracle's error reference; the result follows its current message format, which names the character and the token before it (how the token is printed is illustrative). Oracle Database 19c prints "ORA-00911: invalid character".
SELECT user~id FROM users;
ORA-00911: ~: invalid character after USER
A trailing semicolon sent from application code
Not reproduced here: no Oracle Database is installed for this site. The result is shown in the 19c form from Oracle's error reference; current releases add the character and the preceding token. Whether a driver strips a trailing semicolon itself varies by driver and version, so do not rely on it.
// Java (JDBC): the semicolon belongs to SQL*Plus scripts, not to the statement
stmt.executeQuery("SELECT id, email FROM customers;");
ORA-00911: invalid character
How to prevent it
Use plain identifiers (letters, digits and underscores, starting with a letter) for every table and column, and keep SQL in plain-text files rather than documents. In application code, store statements without terminators and use bind variables instead of building strings.
When a statement fails with ORA-00911 after being copied, retype the quotes and spaces before looking for anything more complicated: invisible characters are the most common cause.
Common questions
How do I fix ORA-00911 invalid character?
Find the character Oracle points at. Put names with special characters in double quotes, remove a trailing semicolon from statements sent by application code, and replace curly quotes or non-breaking spaces with plain characters.
Why does my query work in SQL Developer but fail with ORA-00911 in my application?
Usually because of the semicolon at the end. SQL Developer and SQL*Plus treat it as the end of the statement and do not send it; a driver may pass it to the database as part of the text.
Which characters can an Oracle identifier contain?
Unquoted, only letters, digits and $, _ and #, starting with a letter. Inside double quotes, any character except the double quote and the null character, but the name is then case sensitive and must always be quoted.
Learn more on CodeWithSQL
Official documentation
- ORA-00911 (Oracle Database Error Messages)
- Database object names and qualifiers (Oracle SQL Language Reference 19c)
- Literals: text literals and alternative quoting (Oracle SQL Language Reference 19c)
Last technically reviewed 24 October 2026; examples and diagnostics run on Oracle Database Error Messages reference (26ai, 21c and 19c); not run locally. Messages and explanations follow Oracle's Database Error Messages reference; no Oracle Database was available, so the examples were not run locally.