Db2 SQLCODE

SQLCODE -551: Not authorized for the operation

SQLCODE -551 (SQLSTATE 42501) means the authorization ID Db2 checked doesn't hold the privilege needed for the operation, such as SELECT or UPDATE on a table. The message names the ID, the operation and the object.

Also written as SQL -551, SQLCODE=-551, SQLCODE = -551, db2 -551, sqlstate 42501, SQL0551N, does not have the privilege to perform operation.

What it means

Db2 checks privileges before it lets a statement touch an object. Which ID it checks depends on how the SQL runs, and that is where most of the confusion starts.

For static SQL in a package, Db2 checks the package owner when the package is bound. The people who run the program only need EXECUTE on the plan or package. For dynamic SQL under the default DYNAMICRULES(RUN), Db2 checks the person running it, using the privileges of their primary ID and their secondary IDs (normally their RACF groups) together. A package bound with DYNAMICRULES(BIND) checks the package owner for its dynamic SQL instead.

If none of the IDs Db2 checks holds the privilege, the statement fails with -551, and SQLERRMC lists the ID, the operation and the object. For static SQL bound with VALIDATE(RUN), a privilege the owner lacked at bind time is checked again when the statement runs, and that's when -551 shows up.

Common causes

  • The user, or a RACF group they belong to, was never granted the privilege. This is common with dynamic SQL from SPUFI, QMF, DSNTEP2 or a distributed client.
  • The package owner lacks the privilege. The package was bound with VALIDATE(RUN), so the bind didn't fail and the problem waited until run time.
  • The program runs under a different ID than expected. A batch job's USER, or the AUTHID or AUTHTYPE on a CICS DB2ENTRY, decides which ID Db2 sees.
  • The grant was made to a RACF group, but Db2 isn't receiving that group as a secondary ID for this user.
  • The privilege was revoked, or the table was dropped and created again, which removes every grant on it.
  • Your site uses RACF to control Db2 object access, and the RACF profile for the object has no PERMIT for this user.

How to find the problem

  1. Read the three tokens in the message. They give the ID Db2 checked, the operation it refused and the object.
  2. Check table grants with SELECT GRANTEE, SELECTAUTH, INSERTAUTH, UPDATEAUTH, DELETEAUTH FROM SYSIBM.SYSTABAUTH WHERE TCREATOR = 'PAYPROD' AND TTNAME = 'EMP_SALARY'. Y means the privilege is held, and G means it's held with the grant option.
  3. If the ID in the message is a person, the SQL is dynamic and running under their own authority. If it's the package owner, check OWNER, VALIDATE and DYNAMICRULES for the package in SYSIBM.SYSPACKAGE.
  4. If your site controls Db2 access through RACF, ask the security team to check the profile for the table in the Db2 table class your site uses, such as MDSNTB.

How to fix it

  • Grant the privilege to a RACF group the user belongs to rather than to one person, for example GRANT SELECT ON PAYPROD.EMP_SALARY TO PAYRPT.
  • For static SQL, grant the privilege to the package owner and rebind. Binding with VALIDATE(BIND) makes a missing privilege stop the bind instead of the program.
  • If dynamic SQL should run with the program's authority rather than the user's, consider DYNAMICRULES(BIND). It changes your security model, so agree it with the DBA and security teams.
  • After a table is dropped and created again, rerun every GRANT that was on it. Keep the grants in the same change script as the DDL.
  • If the grant went to a RACF group, check that the user is connected to that group and that your Db2 connection and sign-on exits pass RACF groups as secondary IDs. Group changes take effect at the user's next connection to Db2.

What it looks like

DSNT408I SQLCODE = -551, ERROR:  RPTUSR4 DOES NOT HAVE THE PRIVILEGE TO PERFORM OPERATION
         SELECT ON OBJECT PAYPROD.EMP_SALARY
DSNT418I SQLSTATE   = 42501 SQLSTATE RETURN CODE

Questions

What's the difference between -551 and -552?

-551 is about a privilege on one object, such as SELECT on a table. -552 is about an operation that needs broader authority, such as creating a table or binding a new package.

Why does the program work but my SPUFI query gets -551?

The program's static SQL runs with the package owner's privileges. Your SPUFI query is dynamic and runs with your own, which may not include that table.

What's the difference between -551 and -922?

-922 means you couldn't connect to Db2 or run the plan at all. -551 means you got in but lack a privilege on a specific object.